summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/ChangeLog30
-rw-r--r--zebra/Makefile.am7
-rw-r--r--zebra/client_main.c2
-rw-r--r--zebra/connected.c35
-rw-r--r--zebra/connected.h4
-rw-r--r--zebra/if_linkdetect.c92
-rw-r--r--zebra/interface.c16
-rw-r--r--zebra/interface.h17
-rw-r--r--zebra/ioctl.c37
-rw-r--r--zebra/kernel_null.c6
-rw-r--r--zebra/kernel_socket.c2
-rw-r--r--zebra/linkdetect_null.c28
-rw-r--r--zebra/main.c15
-rw-r--r--zebra/rib.h25
-rw-r--r--zebra/rt.h4
-rw-r--r--zebra/rt_ioctl.c4
-rw-r--r--zebra/rt_netlink.c318
-rw-r--r--zebra/rt_socket.c4
-rw-r--r--zebra/rtadv.c12
-rw-r--r--zebra/zebra.conf.sample2
-rw-r--r--zebra/zebra_rib.c322
-rw-r--r--zebra/zebra_vty.c4
-rw-r--r--zebra/zserv.c6
-rw-r--r--zebra/zserv.h1
24 files changed, 503 insertions, 490 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index d9cae283..341c42a4 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,33 @@
+2008-07-01 Paul Jakma <paul.jakma@sun.com>
+
+ * ioctl.c: (if_get_flags) Deal more gracefully with failure
+ of the BSD link-state SIOCGIFMEDIA ioctl, as some interfaces
+ apparently don't implement it (e.g. tun).
+ Also, make BSD link-state checking be conditional on the
+ 'link-detect' interface configuration flag, as it should be.
+ Fixes bug #465.
+
+2008-06-02 Denis Ovsienko
+
+ * connected.c: (connected_up_ipv4, connected_down_ipv4,
+ connected_up_ipv6, connected_down_ipv6): don't call
+ work_queue_aim_head()
+ * rib.h: adjust RIB_ROUTE_QUEUED macro for meta_queue,
+ declare meta_queue structure
+ * zebra_rib.c: (process_subq, meta_queue_process, rib_meta_queue_add,
+ meta_queue_new) new functions; (rib_queue_add) don't try checking
+ RIB_QUEUE_ADDED flag, rib_meta_queue_add() does it better, take care
+ of the meta queue instead; (rib_queue_init) initialize the meta queue
+ as well; (rib_lookup_and_pushup) don't call work_queue_aim_head();
+ (rib_process) only do actual processing, don't do deallocation;
+ * zserv.h: include meta_queue field into zebra_t structure
+
+2008-05-29 Stephen Hemminger <stephen.hemminger@vyatta.com>
+
+ * rt_netlink.c: (netlink_install_filter) BPF filter to catch and
+ drop responses to zebra's own route messages.
+ (kernel_init) add BPF filter on the netlink socket.
+
2008-02-26 Denis Ovsienko
* zebra_rib.[ch]: (rib_lookup_and_pushup) New function, which makes sure,
that if_set_prefix() has nothing in its way of assigning an address.
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 8977c893..5d8db411 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -10,14 +10,13 @@ LIBCAP = @LIBCAP@
ipforward = @IPFORWARD@
if_method = @IF_METHOD@
if_proc = @IF_PROC@
-link_detect = @LINK_DETECT@
rt_method = @RT_METHOD@
rtread_method = @RTREAD_METHOD@
kernel_method = @KERNEL_METHOD@
other_method = @OTHER_METHOD@
ioctl_method = @IOCTL_METHOD@
-otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) $(link_detect) \
+otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) \
$(rt_method) $(rtread_method) $(kernel_method) $(other_method)
sbin_PROGRAMS = zebra
@@ -30,7 +29,7 @@ zebra_SOURCES = \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
- zebra_vty.c linkdetect_null.c \
+ zebra_vty.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c
noinst_HEADERS = \
@@ -43,7 +42,7 @@ testzebra_LDADD = $(LIBCAP) $(LIB_IPV6) ../lib/libzebra.la
zebra_DEPENDENCIES = $(otherobj)
-EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_linkdetect.c if_netlink.c if_proc.c \
+EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c if_proc.c \
if_sysctl.c ipforward_aix.c ipforward_ews.c ipforward_proc.c \
ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \
rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \
diff --git a/zebra/client_main.c b/zebra/client_main.c
index e59b09d0..c319aac7 100644
--- a/zebra/client_main.c
+++ b/zebra/client_main.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: client_main.c,v 1.1 2002/12/13 20:15:30 paul Exp $
*
* GNU Zebra client test main routine.
* Copyright (C) 1997 Kunihiro Ishiguro
diff --git a/zebra/connected.c b/zebra/connected.c
index ca22a011..b235d8c0 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -36,6 +36,7 @@
#include "zebra/interface.h"
#include "zebra/connected.h"
extern struct zebra_t zebrad;
+
/* withdraw a connected address */
static void
@@ -174,6 +175,7 @@ void
connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
{
struct prefix_ipv4 p;
+ struct in_addr src = ((struct prefix_ipv4 *) ifc->address)->prefix;
if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
return;
@@ -188,21 +190,14 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
if (prefix_ipv4_any (&p))
return;
- /* Always push arriving/departing connected routes into the head of
- * the working queue to make possible proper validation of the rest
- * of the RIB queue (which will contain the whole RIB after the first
- * call to rib_update()).
- */
- work_queue_aim_head (zebrad.ribq, 1);
- rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
- RT_TABLE_MAIN, ifp->metric, 0);
- work_queue_aim_head (zebrad.ribq, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, &src,
+ ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0, RT_SCOPE_LINK);
rib_update ();
}
/* Add connected IPv4 route to the interface. */
-void
+struct connected *
connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
u_char prefixlen, struct in_addr *broad,
const char *label)
@@ -277,10 +272,10 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* nothing to do? */
- if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
- return;
-
+ ifc = connected_implicit_withdraw (ifp, ifc);
connected_announce (ifp, ifc);
+
+ return ifc;
}
void
@@ -302,9 +297,7 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
return;
/* Same logic as for connected_up_ipv4(): push the changes into the head. */
- work_queue_aim_head (zebrad.ribq, 1);
rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
- work_queue_aim_head (zebrad.ribq, 0);
rib_update ();
}
@@ -349,16 +342,14 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
return;
#endif
- work_queue_aim_head (zebrad.ribq, 1);
rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
ifp->metric, 0);
- work_queue_aim_head (zebrad.ribq, 0);
rib_update ();
}
/* Add connected IPv6 route to the interface. */
-void
+struct connected *
connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
u_char prefixlen, struct in6_addr *broad,
const char *label)
@@ -405,10 +396,10 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
if (label)
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
- if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
- return;
-
+ ifc = connected_implicit_withdraw (ifp, ifc);
connected_announce (ifp, ifc);
+
+ return ifc;
}
void
@@ -426,9 +417,7 @@ connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
return;
- work_queue_aim_head (zebrad.ribq, 1);
rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
- work_queue_aim_head (zebrad.ribq, 0);
rib_update ();
}
diff --git a/zebra/connected.h b/zebra/connected.h
index 9595ddb1..8bfe4118 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -26,7 +26,7 @@
extern struct connected *
connected_check (struct interface *ifp, struct prefix *p);
-extern void
+extern struct connected *
connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
u_char prefixlen, struct in_addr *broad,
const char *label);
@@ -39,7 +39,7 @@ extern void connected_up_ipv4 (struct interface *, struct connected *);
extern void connected_down_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
-extern void
+extern struct connected *
connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *address,
u_char prefixlen, struct in6_addr *broad,
const char *label);
diff --git a/zebra/if_linkdetect.c b/zebra/if_linkdetect.c
deleted file mode 100644
index 4f95c16e..00000000
--- a/zebra/if_linkdetect.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Interface link state tracking
- * Copyright (C) 2008 Stephen Hemminger
- *
- * 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 "log.h"
-#include "privs.h"
-#include "prefix.h"
-
-#include "zebra/interface.h"
-
-extern struct zebra_privs_t zserv_privs;
-
-static int
-linkdetect (const char *name, const char *ver, int onoff)
-{
- FILE *fp;
- int save_errno;
- char proc_name[128];
-
- snprintf(proc_name, sizeof(proc_name)-1,
- "/proc/sys/net/%s/conf/%s/link_detect", ver, name);
-
- if ( zserv_privs.change(ZPRIVS_RAISE) )
- zlog_err ("Can't raise privileges, %s", safe_strerror (errno) );
-
- fp = fopen (proc_name, "w");
- save_errno = errno;
- if (!fp)
- {
- if ( zserv_privs.change(ZPRIVS_LOWER) )
- zlog_err ("Can't lower privileges, %s", safe_strerror (errno));
-
- zlog_info("Can't %s link-detect, %s:%s",
- onoff ? "enable" : "disable",
- proc_name, safe_strerror(save_errno));
- return -1;
- }
- else
- {
- fprintf (fp, "%d\n", onoff);
- fclose (fp);
-
- if ( zserv_privs.change(ZPRIVS_LOWER) )
- zlog_err ("Can't lower privileges, %s", safe_strerror (errno));
-
- return onoff;
- }
-}
-
-int
-if_linkdetect_on (const char *name)
-{
- return linkdetect (name, "ipv4", 1);
-}
-
-int
-if_linkdetect_off (const char *name)
-{
- return linkdetect (name, "ipv4", 0);
-}
-
-#ifdef HAVE_IPV6
-int
-if_linkdetect_ipv6_on (const char *name)
-{
- return linkdetect (name, "ipv6", 1);
-}
-
-int
-if_linkdetect_ipv6_off (const char *name)
-{
- return linkdetect (name, "ipv6", 0);
-}
-#endif
diff --git a/zebra/interface.c b/zebra/interface.c
index 916c58a6..74c977a9 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -32,7 +32,6 @@
#include "connected.h"
#include "log.h"
#include "zclient.h"
-#include "ipforward.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
@@ -49,8 +48,7 @@ if_zebra_new_hook (struct interface *ifp)
{
struct zebra_if *zebra_if;
- zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if));
- memset (zebra_if, 0, sizeof (struct zebra_if));
+ zebra_if = XCALLOC (MTYPE_TMP, sizeof (struct zebra_if));
zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC;
@@ -1032,12 +1030,6 @@ DEFUN (linkdetect,
if_was_operative = if_is_operative(ifp);
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
- /* Enable FIB to remove kernel routes as well */
- if_linkdetect_on(ifp->name);
-#ifdef HAVE_IPV6
- if_linkdetect_ipv6_on(ifp->name);
-#endif
-
/* When linkdetection is enabled, if might come down */
if (!if_is_operative(ifp) && if_was_operative) if_down(ifp);
@@ -1061,12 +1053,6 @@ DEFUN (no_linkdetect,
if_was_operative = if_is_operative(ifp);
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
- /* Disable FIB update on link-detect */
- if_linkdetect_off(ifp->name);
-#ifdef HAVE_IPV6
- if_linkdetect_ipv6_off(ifp->name);
-#endif
-
/* Interface may come up after disabling link detection */
if (if_is_operative(ifp) && !if_was_operative) if_up(ifp);
diff --git a/zebra/interface.h b/zebra/interface.h
index 114270e7..0a6b0365 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -234,23 +234,6 @@ extern int interface_list_proc (void);
extern int ifaddr_proc_ipv6 (void);
#endif /* HAVE_PROC_NET_IF_INET6 */
-#ifdef HAVE_LINKDETECT
-extern int if_linkdetect_on (const char *);
-extern int if_linkdetect_off (const char *);
-# ifdef HAVE_IPV6
-extern int if_linkdetect_ipv6_on (const char *);
-extern int if_linkdetect_ipv6_off (const char *);
-# endif
-#else
-#define if_linkdetect_on(name)
-#define if_linkdetect_off(name)
-# ifdef HAVE_IPV6
-#define if_linkdetect_ipv6_on(name)
-#define if_linkdetect_ipv6_off(name)
-# endif
-#endif
-
-
#ifdef BSDI
extern int if_kvm_get_mtu (struct interface *);
#endif /* BSDI */
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
index d536771a..5cf9e7b0 100644
--- a/zebra/ioctl.c
+++ b/zebra/ioctl.c
@@ -362,22 +362,29 @@ if_get_flags (struct interface *ifp)
return;
}
#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
- (void) memset(&ifmr, 0, sizeof(ifmr));
- strncpy (&ifmr.ifm_name, ifp->name, IFNAMSIZ);
- if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
- {
- zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
- return;
- }
- if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
+
+ /* Per-default, IFF_RUNNING is held high, unless link-detect says
+ * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
+ * following practice on Linux and Solaris kernels
+ */
+ SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+
+ if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
{
- if (ifmr.ifm_status & IFM_ACTIVE)
- SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
- else
- UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
- }
- else /* Force always up */
- SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ strncpy (&ifmr.ifm_name, ifp->name, IFNAMSIZ);
+
+ /* Seems not all interfaces implement this ioctl */
+ if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
+ zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
+ else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
+ {
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+ else
+ UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+ }
+ }
#endif /* HAVE_BSD_LINK_DETECT */
if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff));
diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c
index 94b7b3c7..c72bbd09 100644
--- a/zebra/kernel_null.c
+++ b/zebra/kernel_null.c
@@ -12,9 +12,9 @@ int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; }
#pragma weak kernel_delete_ipv4 = kernel_add_ipv4
int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; }
#pragma weak kernel_delete_ipv6 = kernel_add_ipv6
-int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
-{ return 0; }
+void kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ unsigned int index, int table)
+{ }
int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d)
{ return 0; }
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 2e04b031..e77b9b78 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -126,7 +126,7 @@ extern struct zebra_t zebrad;
(LEN) = 0; \
}
/* Routing socket message types. */
-struct message rtm_type_str[] =
+const struct message rtm_type_str[] =
{
{RTM_ADD, "RTM_ADD"},
{RTM_DELETE, "RTM_DELETE"},
diff --git a/zebra/linkdetect_null.c b/zebra/linkdetect_null.c
deleted file mode 100644
index 1f160c8e..00000000
--- a/zebra/linkdetect_null.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* NULL method for testing. */
-
-#include <zebra.h>
-
-
-int
-if_linkdetect_on (const char *name)
-{
- return 0;
-}
-
-int
-if_linkdetect_off (const char *name)
-{
- return 0;
-}
-
-int
-if_linkdetect_ipv6_on (const char *name)
-{
- return 0;
-}
-
-int
-if_linkdetect_ipv6_off (const char *name)
-{
- return 0;
-}
diff --git a/zebra/main.c b/zebra/main.c
index 6019260f..ac0637b6 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -63,12 +63,16 @@ int keep_kernel_mode = 0;
u_int32_t nl_rcvbufsize = 0;
#endif /* HAVE_NETLINK */
+/* Manage system routes. */
+extern int rib_system_routes;
+
/* Command line options. */
struct option longopts[] =
{
{ "batch", no_argument, NULL, 'b'},
{ "daemon", no_argument, NULL, 'd'},
{ "keep_kernel", no_argument, NULL, 'k'},
+ { "rib_system", no_argument, NULL, 'S'},
{ "log_mode", no_argument, NULL, 'l'},
{ "config_file", required_argument, NULL, 'f'},
{ "pid_file", required_argument, NULL, 'i'},
@@ -131,6 +135,7 @@ usage (char *progname, int status)
"-i, --pid_file Set process identifier file name\n"\
"-k, --keep_kernel Don't delete old routes which installed by "\
"zebra.\n"\
+ "-S, --system Manage all routes on link transistions\n"
"-l, --log_mode Set verbose log mode flag\n"\
"-C, --dryrun Check configuration for validity and exit\n"\
"-A, --vty_addr Set vty's bind address\n"\
@@ -231,9 +236,9 @@ main (int argc, char **argv)
int opt;
#ifdef HAVE_NETLINK
- opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vs:C", longopts, 0);
+ opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vs:CS", longopts, 0);
#else
- opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vC", longopts, 0);
+ opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vCS", longopts, 0);
#endif /* HAVE_NETLINK */
if (opt == EOF)
@@ -251,6 +256,9 @@ main (int argc, char **argv)
case 'k':
keep_kernel_mode = 1;
break;
+ case 'S':
+ rib_system_routes = 1;
+ break;
case 'C':
dryrun = 1;
break;
@@ -275,7 +283,8 @@ main (int argc, char **argv)
break;
}
vty_port = atoi (optarg);
- vty_port = (vty_port ? vty_port : ZEBRA_VTY_PORT);
+ if (vty_port <= 0 || vty_port > 0xffff)
+ vty_port = ZEBRA_VTY_PORT;
break;
case 'r':
retain_mode = 1;
diff --git a/zebra/rib.h b/zebra/rib.h
index f3572ffa..c39afa73 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -60,9 +60,12 @@ struct rib
/* Type for this route. < ZEBRA_ROUTE_MAX */
u_int8_t type;
+ /* Scope for this route. */
+ u_int8_t scope;
+
/* Status Flags for the *route_node*, but kept in the head RIB.. */
u_char rn_status;
-#define RIB_ROUTE_QUEUED (1 << 0)
+#define RIB_ROUTE_QUEUED(x) (1 << (x))
/* Distance. */
u_char distance;
@@ -76,6 +79,7 @@ struct rib
/* RIB internal status */
u_char status;
#define RIB_ENTRY_REMOVED (1 << 0)
+#define RIB_ENTRY_PRESERVE (2 << 0)
/* Nexthop information. */
u_char nexthop_num;
@@ -83,6 +87,20 @@ struct rib
u_char nexthop_fib_num;
};
+/* meta-queue structure:
+ * sub-queue 0: connected, kernel
+ * sub-queue 1: static
+ * sub-queue 2: RIP, RIPng, OSPF, OSPF6, IS-IS
+ * sub-queue 3: iBGP, eBGP
+ * sub-queue 4: any other origin (if any)
+ */
+#define MQ_SIZE 5
+struct meta_queue
+{
+ struct list *subq[MQ_SIZE];
+ u_int32_t size; /* sum of lengths of all subqueues */
+};
+
/* Static route information. */
struct static_ipv4
{
@@ -207,7 +225,8 @@ struct vrf
struct route_table *stable[AFI_MAX][SAFI_MAX];
};
-extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
+extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int,
+ struct in_addr *);
extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
extern struct nexthop *nexthop_blackhole_add (struct rib *);
extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
@@ -236,7 +255,7 @@ extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t i
extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct in_addr *gate, struct in_addr *src,
unsigned int ifindex, u_int32_t vrf_id,
- u_int32_t, u_char);
+ u_int32_t metric, u_int8_t distance, u_int8_t scope);
extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
diff --git a/zebra/rt.h b/zebra/rt.h
index 8bfe5a42..8b975558 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -36,8 +36,8 @@ extern int kernel_address_delete_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
extern int kernel_add_ipv6 (struct prefix *, struct rib *);
extern int kernel_delete_ipv6 (struct prefix *, struct rib *);
-extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table);
+extern void kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ unsigned int index, int table);
#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c
index a5d588c7..d39ec4df 100644
--- a/zebra/rt_ioctl.c
+++ b/zebra/rt_ioctl.c
@@ -553,8 +553,8 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
/* Delete IPv6 route from the kernel. */
int
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
- return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
+ return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, 0;
}
#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index ba66ab90..f9f90224 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -53,7 +53,7 @@ struct nlsock
} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
-static struct message nlmsg_str[] = {
+static const struct message nlmsg_str[] = {
{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_DELROUTE, "RTM_DELROUTE"},
{RTM_GETROUTE, "RTM_GETROUTE"},
@@ -87,32 +87,11 @@ extern struct zebra_privs_t zserv_privs;
extern u_int32_t nl_rcvbufsize;
-/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
- names and ifindex values. */
-static void
-set_ifindex(struct interface *ifp, unsigned int ifi_index)
-{
- struct interface *oifp;
+extern int rib_system_routes;
- if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
- {
- if (ifi_index == IFINDEX_INTERNAL)
- zlog_err("Netlink is setting interface %s ifindex to reserved "
- "internal value %u", ifp->name, ifi_index);
- else
- {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("interface index %d was renamed from %s to %s",
- ifi_index, oifp->name, ifp->name);
- if (if_is_operative(oifp))
- zlog_err("interface rename detected on up interface: index %d "
- "was renamed from %s to %s, results are uncertain!",
- ifi_index, oifp->name, ifp->name);
- if_delete_update(oifp);
- }
- }
- ifp->ifindex = ifi_index;
-}
+static void
+netlink_delroute (int family, void *dest, int length, void *gate,
+ int index, int table, int proto);
static int
netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
@@ -316,6 +295,13 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
return -1;
}
+ /* JF: Ignore messages that aren't from the kernel */
+ if ( snl.nl_pid != 0 )
+ {
+ zlog_debug ("Ignoring message from pid %u", snl.nl_pid );
+ continue;
+ }
+
for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
h = NLMSG_NEXT (h, status))
{
@@ -467,14 +453,28 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
#endif /* IFLA_WIRELESS */
if (tb[IFLA_IFNAME] == NULL)
- return -1;
+ {
+ zlog_err("%s: missing interface name in message", __func__);
+ return -1;
+ }
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
+ if (ifi->ifi_index == IFINDEX_INTERNAL)
+ {
+ zlog_err("%s: reserved ifindex", __func__);
+ return -1;
+ }
+
/* Add interface. */
- ifp = if_get_by_name (name);
- set_ifindex(ifp, ifi->ifi_index);
+ ifp = if_lookup_by_index(ifi->ifi_index);
+ if (!ifp)
+ {
+ ifp = if_create(name, strlen(name));
+ ifp->ifindex = ifi->ifi_index;
+ }
+ strncpy(ifp->name, name, INTERFACE_NAMSIZ);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
+ ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
/* Hardware type and address. */
@@ -528,7 +528,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
#ifdef HAVE_IPV6
&& ifa->ifa_family != AF_INET6
#endif /* HAVE_IPV6 */
- )
+ )
return 0;
if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
@@ -553,7 +553,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
char buf[BUFSIZ];
zlog_debug ("netlink_interface_addr %s %s:",
- lookup (nlmsg_str, h->nlmsg_type), ifp->name);
+ lookup (nlmsg_str, h->nlmsg_type), ifp->name);
if (tb[IFA_LOCAL])
zlog_debug (" IFA_LOCAL %s/%d",
inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
@@ -619,9 +619,25 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (ifa->ifa_family == AF_INET)
{
if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv4 (ifp, flags,
- (struct in_addr *) addr, ifa->ifa_prefixlen,
- (struct in_addr *) broad, label);
+ {
+ struct connected *ifc;
+ ifc = connected_add_ipv4 (ifp, flags,
+ (struct in_addr *) addr, ifa->ifa_prefixlen,
+ (struct in_addr *) broad, label);
+
+ /* If address added, but interface is down,
+ then remove the FIB entry from kernel.
+ */
+ if (rib_system_routes && ifc && !if_is_operative (ifp))
+ {
+ struct prefix_ipv4 p;
+ PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
+ apply_mask_ipv4 (&p);
+
+ netlink_delroute (p.family, &p.prefix, p.prefixlen, NULL,
+ ifp->ifindex, RT_TABLE_MAIN, RTPROT_KERNEL);
+ }
+ }
else
connected_delete_ipv4 (ifp, flags,
(struct in_addr *) addr, ifa->ifa_prefixlen,
@@ -631,9 +647,9 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (ifa->ifa_family == AF_INET6)
{
if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv6 (ifp, flags,
- (struct in6_addr *) addr, ifa->ifa_prefixlen,
- (struct in6_addr *) broad, label);
+ connected_add_ipv6 (ifp, flags,
+ (struct in6_addr *) addr, ifa->ifa_prefixlen,
+ (struct in6_addr *) broad, label);
else
connected_delete_ipv6 (ifp,
(struct in6_addr *) addr, ifa->ifa_prefixlen,
@@ -704,7 +720,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
src = NULL;
if (tb[RTA_OIF])
- index = *(int *) RTA_DATA (tb[RTA_OIF]);
+ index = *(uint32_t *) RTA_DATA (tb[RTA_OIF]);
if (tb[RTA_DST])
dest = RTA_DATA (tb[RTA_DST]);
@@ -719,7 +735,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
gate = RTA_DATA (tb[RTA_GATEWAY]);
if (tb[RTA_PRIORITY])
- metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+ metric = *(uint32_t *) RTA_DATA(tb[RTA_PRIORITY]);
if (rtm->rtm_family == AF_INET)
{
@@ -728,7 +744,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
+ table, metric, 0, rtm->rtm_scope);
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
@@ -746,7 +763,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
return 0;
}
-struct message rtproto_str[] = {
+static const struct message rtproto_str[] = {
{RTPROT_REDIRECT, "redirect"},
{RTPROT_KERNEL, "kernel"},
{RTPROT_BOOT, "boot"},
@@ -835,7 +852,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
src = NULL;
if (tb[RTA_OIF])
- index = *(int *) RTA_DATA (tb[RTA_OIF]);
+ index = *(uint32_t *) RTA_DATA (tb[RTA_OIF]);
if (tb[RTA_DST])
dest = RTA_DATA (tb[RTA_DST]);
@@ -866,7 +883,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0,
+ 0, rtm->rtm_scope);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
@@ -941,70 +959,94 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
#endif /* IFLA_WIRELESS */
if (tb[IFLA_IFNAME] == NULL)
- return -1;
+ {
+ zlog_err("%s: missing interface name", __func__);
+ return -1;
+ }
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
/* Add interface. */
if (h->nlmsg_type == RTM_NEWLINK)
{
unsigned long new_flags = ifi->ifi_flags & 0x0000fffff;
- ifp = if_lookup_by_name (name);
+ unsigned int mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
+ ifp = if_lookup_by_index (ifi->ifi_index);
+ /* New interface */
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
if (ifp == NULL)
- ifp = if_get_by_name (name);
+ {
+ ifp = if_create(name, strlen(name));
+ ifp->ifindex = ifi->ifi_index;
+ ifp->metric = 1;
+ }
+ else if (strcmp(ifp->name, name) != 0)
+ {
+ strncpy(ifp->name, name, INTERFACE_NAMSIZ);
+ }
zlog_info ("interface %s index %d %s added.",
name, ifi->ifi_index, if_flag_dump(new_flags));
- set_ifindex(ifp, ifi->ifi_index);
ifp->flags = new_flags;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
+ ifp->mtu6 = ifp->mtu = mtu;
- /* If new link is added. */
- if_add_update (ifp);
+ /* If new link is added. */
+ if_add_update (ifp);
}
- else
- {
- /* Interface status change. */
- set_ifindex(ifp, ifi->ifi_index);
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
+ /* Interface status change. */
+ else if (new_flags != ifp->flags)
+ {
+ ifp->mtu6 = ifp->mtu = mtu;
- if (new_flags != ifp->flags)
- {
- zlog_info ("interface %s index %d changed %s.",
- name, ifi->ifi_index, if_flag_dump(new_flags));
+ zlog_info ("interface %s index %d changed %s.",
+ name, ifi->ifi_index, if_flag_dump(new_flags));
- if (if_is_operative (ifp))
- {
- ifp->flags = new_flags;
- if (!if_is_operative (ifp))
- if_down (ifp);
- else
- /* Must notify client daemons of new interface status. */
- zebra_interface_up_update (ifp);
- }
+ if (if_is_operative (ifp))
+ {
+ ifp->flags = new_flags;
+ if (!if_is_operative (ifp))
+ if_down (ifp);
else
- {
- ifp->flags = new_flags;
- if (if_is_operative (ifp))
- if_up (ifp);
- }
+ /* Must notify client daemons of new interface status. */
+ zebra_interface_up_update (ifp);
}
- }
+ else
+ {
+ ifp->flags = new_flags;
+ if (if_is_operative (ifp))
+ if_up (ifp);
+ }
+ }
+ /* Interface name change */
+ else if (strcmp(ifp->name, name) != 0)
+ {
+ ifp->mtu = ifp->mtu6 = mtu;
+ zlog_info("interface index %d was renamed from %s to %s",
+ ifi->ifi_index, ifp->name, name);
+
+ strncpy(ifp->name, name, INTERFACE_NAMSIZ);
+ rib_update();
+ }
+ /* Interface mtu change */
+ else if (mtu != ifp->mtu)
+ {
+ zlog_info("interface index %d mtu changed from %u to %u",
+ ifp->mtu, mtu);
+ ifp->mtu = ifp->mtu6 = mtu;
+ if (if_is_operative (ifp))
+ zebra_interface_up_update (ifp);
+ }
}
else
{
// RTM_DELLINK.
- ifp = if_lookup_by_name (name);
-
+ ifp = if_lookup_by_index (ifi->ifi_index);
if (ifp == NULL)
{
- zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
- name);
+ zlog (NULL, LOG_WARNING, "interface %s index %d is deleted but can't find",
+ name, ifi->ifi_index);
return 0;
}
else
@@ -1012,6 +1054,7 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
name, ifi->ifi_index);
if_delete_update (ifp);
+ if_delete (ifp);
}
return 0;
}
@@ -1205,11 +1248,6 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
/* Request an acknowledgement by setting NLM_F_ACK */
n->nlmsg_flags |= NLM_F_ACK;
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
- lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
- n->nlmsg_seq);
-
/* Send message to netlink interface. */
if (zserv_privs.change (ZPRIVS_RAISE))
zlog (NULL, LOG_ERR, "Can't raise privileges");
@@ -1234,15 +1272,11 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
}
/* Routing table change via netlink interface. */
-static int
-netlink_route (int cmd, int family, void *dest, int length, void *gate,
- int index, int zebra_flags, int table)
+static void
+netlink_delroute (int family, void *dest, int length, void *gate,
+ int index, int table, int proto)
{
- int ret;
- int bytelen;
- struct sockaddr_nl snl;
- int discard;
-
+ int bytelen = (family == AF_INET ? 4 : 16);
struct
{
struct nlmsghdr n;
@@ -1252,60 +1286,25 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate,
memset (&req, 0, sizeof req);
- bytelen = (family == AF_INET ? 4 : 16);
-
req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
- req.n.nlmsg_type = cmd;
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_DELROUTE;
req.r.rtm_family = family;
+ req.r.rtm_scope = RT_SCOPE_NOWHERE;
req.r.rtm_table = table;
req.r.rtm_dst_len = length;
- if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- || (zebra_flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
-
- if (cmd == RTM_NEWROUTE)
- {
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-
- if (discard)
- {
- if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (zebra_flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
- }
- else
- req.r.rtm_type = RTN_UNICAST;
- }
-
if (dest)
addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
- if (!discard)
- {
- if (gate)
- addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
- if (index > 0)
- addattr32 (&req.n, sizeof req, RTA_OIF, index);
- }
+ if (gate)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
- /* Destination netlink address. */
- memset (&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
+ if (index > 0)
+ addattr32 (&req.n, sizeof req, RTA_OIF, index);
/* Talk to netlink socket. */
- ret = netlink_talk (&req.n, &netlink_cmd);
- if (ret < 0)
- return -1;
-
- return 0;
+ netlink_talk (&req.n, &netlink_cmd);
}
/* Routing table change via netlink interface. */
@@ -1342,11 +1341,22 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
else
discard = 0;
+ switch (rib->type) {
+ case ZEBRA_ROUTE_KERNEL:
+ /* FIXME: should remember original protocol from RTM_NEWLINK */
+ req.r.rtm_protocol = RTPROT_BOOT;
+ break;
+ case ZEBRA_ROUTE_CONNECT:
+ req.r.rtm_protocol = RTPROT_KERNEL;
+ break;
+ default:
+ req.r.rtm_protocol = RTPROT_ZEBRA;
+ }
+
+ req.r.rtm_scope = rib->scope;
+
if (cmd == RTM_NEWROUTE)
{
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-
if (discard)
{
if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
@@ -1362,8 +1372,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
- /* Metric. */
- addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
+ if (rib->type != ZEBRA_ROUTE_CONNECT)
+ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
if (discard)
{
@@ -1762,12 +1772,12 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
}
/* Delete IPv6 route from the kernel. */
-int
+void
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
- return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
- dest->prefixlen, gate, index, flags, table);
+ netlink_delroute (AF_INET6, &dest->prefix,
+ dest->prefixlen, gate, index, table, RTPROT_ZEBRA);
}
#endif /* HAVE_IPV6 */
@@ -1856,19 +1866,13 @@ kernel_read (struct thread *thread)
static void netlink_install_filter (int sock, __u32 pid)
{
struct sock_filter filter[] = {
- /* 0: ldh [4] */
- BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
- /* 1: jeq 0x18 jt 3 jf 6 */
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
- /* 2: jeq 0x19 jt 3 jf 6 */
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
- /* 3: ldw [12] */
+ /* 0: ldw [12] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
- /* 4: jeq XX jt 5 jf 6 */
+ /* 1: jeq XX jt 2 jf 3 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
- /* 5: ret 0 (skip) */
+ /* 2: ret 0 (skip) */
BPF_STMT(BPF_RET|BPF_K, 0),
- /* 6: ret 0xffff (keep) */
+ /* 3: ret 0xffff (keep) */
BPF_STMT(BPF_RET|BPF_K, 0xffff),
};
@@ -1877,7 +1881,7 @@ static void netlink_install_filter (int sock, __u32 pid)
.filter = filter,
};
- if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
+ if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
}
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index 1b8ded7e..9bbecb95 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -509,13 +509,13 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
/* Delete IPv6 route from the kernel. */
int
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
int route;
if (zserv_privs.change(ZPRIVS_RAISE))
zlog (NULL, LOG_ERR, "Can't raise privileges");
- route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
+ route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index);
if (zserv_privs.change(ZPRIVS_LOWER))
zlog (NULL, LOG_ERR, "Can't lower privileges");
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 0097e28f..86956ed7 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -84,10 +84,7 @@ struct rtadv *rtadv = NULL;
static struct rtadv *
rtadv_new (void)
{
- struct rtadv *new;
- new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
- memset (new, 0, sizeof (struct rtadv));
- return new;
+ return XCALLOC (MTYPE_TMP, sizeof (struct rtadv));
}
#if 0
@@ -531,12 +528,7 @@ rtadv_make_socket (void)
static struct rtadv_prefix *
rtadv_prefix_new ()
{
- struct rtadv_prefix *new;
-
- new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
- memset (new, 0, sizeof (struct rtadv_prefix));
-
- return new;
+ return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
}
static void
diff --git a/zebra/zebra.conf.sample b/zebra/zebra.conf.sample
index cf135281..a5d0732f 100644
--- a/zebra/zebra.conf.sample
+++ b/zebra/zebra.conf.sample
@@ -2,7 +2,7 @@
!
! zebra sample configuration file
!
-! $Id$
+! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
!
hostname Router
password zebra
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index a511577b..69249779 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -44,6 +44,9 @@
/* Default rtm_table for all clients */
extern struct zebra_t zebrad;
+/* Should kernel routes be removed on link down? */
+int rib_system_routes = 0;
+
/* Hold time for RIB process, should be very minimal.
* it is useful to able to set it otherwise for testing, hence exported
* as global here for test-rig code.
@@ -209,14 +212,16 @@ nexthop_free (struct nexthop *nexthop)
}
struct nexthop *
-nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
+nexthop_ifindex_add (struct rib *rib, unsigned int ifindex,
+ struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IFINDEX;
nexthop->ifindex = ifindex;
+ if (src)
+ nexthop->src.ipv4 = *src;
nexthop_add (rib, nexthop);
@@ -228,8 +233,7 @@ nexthop_ifname_add (struct rib *rib, char *ifname)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IFNAME;
nexthop->ifname = XSTRDUP (0, ifname);
@@ -243,8 +247,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4;
nexthop->gate.ipv4 = *ipv4;
if (src)
@@ -261,8 +264,7 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
if (src)
@@ -280,8 +282,7 @@ nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6;
nexthop->gate.ipv6 = *ipv6;
@@ -296,8 +297,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifname = XSTRDUP (0, ifname);
@@ -313,8 +313,7 @@ nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
@@ -330,8 +329,7 @@ nexthop_blackhole_add (struct rib *rib)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
@@ -444,7 +442,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (nexthop->type == NEXTHOP_TYPE_IPV4)
nexthop->ifindex = newhop->ifindex;
}
- else
+ else
{
if (nexthop->ifindex != newhop->ifindex ||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -453,8 +451,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
return 1;
}
}
- else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) ||
- match->type == ZEBRA_ROUTE_STATIC)
+ else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)
+ || match->type == ZEBRA_ROUTE_STATIC)
{
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
@@ -479,8 +477,6 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
|| newhop->ifindex != nexthop->ifindex
|| nexthop->gate.ipv4.s_addr != newhop->gate.ipv4.s_addr)
SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
-
-
return 1;
}
return 0;
@@ -573,7 +569,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = newhop->ifindex;
}
- else
+ else
{
if (nexthop->ifindex != newhop->ifindex ||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -582,7 +578,8 @@ nexthop_active_ipv6 (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_STATIC)
{
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
@@ -607,8 +604,8 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
}
else if (! CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
|| newhop->ifindex != nexthop->ifindex
- || !IPV6_ADDR_SAME(&nexthop->gate.ipv6,
- &newhop->gate.ipv4))
+ || !IPV6_ADDR_SAME(&nexthop->gate.ipv6,
+ &newhop->gate.ipv6))
SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
return 1;
@@ -654,12 +651,11 @@ rib_match_ipv4 (struct in_addr addr)
for (match = rn->info; match; match = match->next)
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
- continue;
+ continue;
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
break;
}
-
/* If there is no selected route or matched route is EGP, go up
tree. */
if (! match
@@ -710,7 +706,6 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
/* Unlock node. */
route_unlock_node (rn);
- /* Pick up selected route. */
for (match = rn->info; match; match = match->next)
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
@@ -786,24 +781,24 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
/* Ok, we have a cood candidate, let's check it's nexthop list... */
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
- {
- /* We are happy with either direct or recursive hexthop */
- if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr ||
- nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr)
- return ZEBRA_RIB_FOUND_EXACT;
- else
{
- if (IS_ZEBRA_DEBUG_RIB)
- {
- char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
- inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN);
- zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
- }
- return ZEBRA_RIB_FOUND_NOGATE;
+ /* We are happy with either direct or recursive hexthop */
+ if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr ||
+ nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr)
+ return ZEBRA_RIB_FOUND_EXACT;
+ else
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
+ inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
+ inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
+ inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN);
+ zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
+ }
+ return ZEBRA_RIB_FOUND_NOGATE;
+ }
}
- }
return ZEBRA_RIB_NOTFOUND;
}
@@ -838,7 +833,7 @@ rib_match_ipv6 (struct in6_addr *addr)
for (match = rn->info; match; match = match->next)
{
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
- continue;
+ continue;
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
break;
}
@@ -872,8 +867,10 @@ rib_match_ipv6 (struct in6_addr *addr)
}
#endif /* HAVE_IPV6 */
-#define RIB_SYSTEM_ROUTE(R) \
+#define RIB_SYSTEM_ROUTE(R) \
((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+#define RIB_SHOULD_UPDATE(R) \
+ (! CHECK_FLAG((R)->status, RIB_ENTRY_PRESERVE) )
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
@@ -884,7 +881,6 @@ rib_match_ipv6 (struct in6_addr *addr)
*
* The return value is the final value of 'ACTIVE' flag.
*/
-
static int
nexthop_active_check (struct route_node *rn, struct rib *rib,
struct nexthop *nexthop, int set)
@@ -900,7 +896,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
{
case NEXTHOP_TYPE_IFINDEX:
ifp = if_lookup_by_index (nexthop->ifindex);
- if (ifp && if_is_operative (ifp))
+ if (ifp && if_is_operative(ifp))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -909,7 +905,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
family = AFI_IP6;
case NEXTHOP_TYPE_IFNAME:
ifp = if_lookup_by_name (nexthop->ifname);
- if (ifp && if_is_operative (ifp))
+ if (ifp && if_is_operative(ifp))
{
if (set)
nexthop->ifindex = ifp->ifindex;
@@ -943,7 +939,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6))
{
ifp = if_lookup_by_index (nexthop->ifindex);
- if (ifp && if_is_operative (ifp))
+ if (ifp && if_is_operative(ifp))
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -972,7 +968,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
rmap = 0;
- if (rib->type < ZEBRA_ROUTE_MAX && proto_rm[family][rib->type])
+ if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
+ proto_rm[family][rib->type])
rmap = route_map_lookup_by_name (proto_rm[family][rib->type]);
if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
@@ -1056,8 +1053,6 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
break;
#ifdef HAVE_IPV6
case AF_INET6:
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug ("%s: calling kernel_delete_ipv4 (%p, %p)", __func__, rn, rib);
ret = kernel_delete_ipv6 (&rn->p, rib);
break;
#endif /* HAVE_IPV6 */
@@ -1076,7 +1071,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
{
redistribute_delete (&rn->p, rib);
- if (! RIB_SYSTEM_ROUTE (rib))
+ if (RIB_SHOULD_UPDATE (rib))
rib_uninstall_kernel (rn, rib);
UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
}
@@ -1085,15 +1080,14 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
static void rib_unlink (struct route_node *, struct rib *);
/* Core function for processing routing information base. */
-static wq_item_status
-rib_process (struct work_queue *wq, void *data)
+static void
+rib_process (struct route_node *rn)
{
struct rib *rib;
struct rib *next;
struct rib *fib = NULL;
struct rib *select = NULL;
struct rib *del = NULL;
- struct route_node *rn = data;
int installed = 0;
struct nexthop *nexthop = NULL;
char buf[INET6_ADDRSTRLEN];
@@ -1202,17 +1196,17 @@ rib_process (struct work_queue *wq, void *data)
if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))
{
redistribute_delete (&rn->p, select);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (RIB_SHOULD_UPDATE (select))
rib_uninstall_kernel (rn, select);
/* Set real nexthop. */
nexthop_active_update (rn, select, 1);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (RIB_SHOULD_UPDATE (select))
rib_install_kernel (rn, select);
redistribute_add (&rn->p, select);
}
- else if (! RIB_SYSTEM_ROUTE (select))
+ else if (RIB_SHOULD_UPDATE (select))
{
/* Housekeeping code to deal with
race conditions in kernel with linux
@@ -1243,7 +1237,7 @@ rib_process (struct work_queue *wq, void *data)
zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__,
buf, rn->p.prefixlen, fib);
redistribute_delete (&rn->p, fib);
- if (! RIB_SYSTEM_ROUTE (fib))
+ if (RIB_SHOULD_UPDATE (fib))
rib_uninstall_kernel (rn, fib);
UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
@@ -1263,7 +1257,7 @@ rib_process (struct work_queue *wq, void *data)
/* Set real nexthop. */
nexthop_active_update (rn, select, 1);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (RIB_SHOULD_UPDATE (select))
rib_install_kernel (rn, select);
SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
redistribute_add (&rn->p, select);
@@ -1281,10 +1275,100 @@ rib_process (struct work_queue *wq, void *data)
end:
if (IS_ZEBRA_DEBUG_RIB_Q)
zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn);
- if (rn->info)
- UNSET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED);
- route_unlock_node (rn); /* rib queue lock */
- return WQ_SUCCESS;
+}
+
+/* Take a list of route_node structs and return 1, if there was a record
+ * picked from it and processed by rib_process(). Don't process more,
+ * than one RN record; operate only in the specified sub-queue.
+ */
+static unsigned int
+process_subq (struct list * subq, u_char qindex)
+{
+ struct listnode *lnode = listhead (subq);
+ struct route_node *rnode;
+
+ if (!lnode)
+ return 0;
+
+ rnode = listgetdata (lnode);
+ rib_process (rnode);
+
+ if (rnode->info) /* The first RIB record is holding the flags bitmask. */
+ UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex));
+
+ route_unlock_node (rnode);
+ list_delete_node (subq, lnode);
+ return 1;
+}
+
+/* Dispatch the meta queue by picking, processing and unlocking the next RN from
+ * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
+ * is pointed to the meta queue structure.
+ */
+static wq_item_status
+meta_queue_process (struct work_queue *dummy, void *data)
+{
+ struct meta_queue * mq = data;
+ unsigned i;
+
+ for (i = 0; i < MQ_SIZE; i++)
+ if (process_subq (mq->subq[i], i))
+ {
+ mq->size--;
+ break;
+ }
+ return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
+}
+
+/* Map from rib types to queue type (priority) in meta queue */
+static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
+ [ZEBRA_ROUTE_SYSTEM] = 4,
+ [ZEBRA_ROUTE_KERNEL] = 0,
+ [ZEBRA_ROUTE_CONNECT] = 0,
+ [ZEBRA_ROUTE_STATIC] = 1,
+ [ZEBRA_ROUTE_RIP] = 2,
+ [ZEBRA_ROUTE_RIPNG] = 2,
+ [ZEBRA_ROUTE_OSPF] = 2,
+ [ZEBRA_ROUTE_OSPF6] = 2,
+ [ZEBRA_ROUTE_ISIS] = 2,
+ [ZEBRA_ROUTE_BGP] = 3,
+ [ZEBRA_ROUTE_HSLS] = 4,
+};
+
+/* Look into the RN and queue it into one or more priority queues,
+ * increasing the size for each data push done.
+ */
+static void
+rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
+{
+ struct rib *rib;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
+
+ for (rib = rn->info; rib; rib = rib->next)
+ {
+ u_char qindex = meta_queue_map[rib->type];
+
+ /* Invariant: at this point we always have rn->info set. */
+ if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)))
+ {
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u",
+ __func__, buf, rn->p.prefixlen, rn, qindex);
+ continue;
+ }
+
+ SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex));
+ listnode_add (mq->subq[qindex], rn);
+ route_lock_node (rn);
+ mq->size++;
+
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u",
+ __func__, buf, rn->p.prefixlen, rn, qindex);
+ }
}
/* Add route_node to work queue and schedule processing */
@@ -1306,17 +1390,6 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
return;
}
- /* Route-table node already queued, so nothing to do */
- if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED))
- {
- if (IS_ZEBRA_DEBUG_RIB_Q)
- zlog_debug ("%s: %s/%d: rn %p already queued", __func__, buf,
- rn->p.prefixlen, rn);
- return;
- }
-
- route_lock_node (rn); /* rib queue lock */
-
if (IS_ZEBRA_DEBUG_RIB_Q)
zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen);
@@ -1325,13 +1398,21 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
if (zebra->ribq == NULL)
{
zlog_err ("%s: work_queue does not exist!", __func__);
- route_unlock_node (rn);
return;
}
-
- work_queue_add (zebra->ribq, rn);
- SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED);
+ /* The RIB queue should normally be either empty or holding the only work_queue_item
+ * element. In the latter case this element would hold a pointer to the meta queue
+ * structure, which must be used to actually queue the route nodes to process. So
+ * create the MQ holder, if necessary, then push the work into it in any case.
+ * This semantics was introduced after 0.99.9 release.
+ */
+
+ /* Should I invent work_queue_empty() and use it, or it's Ok to do as follows? */
+ if (!zebra->ribq->items->count)
+ work_queue_add (zebra->ribq, zebra->mq);
+
+ rib_meta_queue_add (zebra->mq, rn);
if (IS_ZEBRA_DEBUG_RIB_Q)
zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn);
@@ -1339,6 +1420,27 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
return;
}
+/* Create new meta queue.
+ A destructor function doesn't seem to be necessary here.
+ */
+static struct meta_queue *
+meta_queue_new (void)
+{
+ struct meta_queue *new;
+ unsigned i;
+
+ new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue));
+ assert(new);
+
+ for (i = 0; i < MQ_SIZE; i++)
+ {
+ new->subq[i] = list_new ();
+ assert(new->subq[i]);
+ }
+
+ return new;
+}
+
/* initialise zebra rib work queue */
static void
rib_queue_init (struct zebra_t *zebra)
@@ -1353,12 +1455,17 @@ rib_queue_init (struct zebra_t *zebra)
}
/* fill in the work queue spec */
- zebra->ribq->spec.workfunc = &rib_process;
+ zebra->ribq->spec.workfunc = &meta_queue_process;
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__);
+ return;
+ }
return;
}
@@ -1516,7 +1623,7 @@ int
rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct in_addr *gate, struct in_addr *src,
unsigned int ifindex, u_int32_t vrf_id,
- u_int32_t metric, u_char distance)
+ u_int32_t metric, u_int8_t distance, u_int8_t scope)
{
struct rib *rib;
struct rib *same = NULL;
@@ -1524,6 +1631,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct route_node *rn;
struct nexthop *nexthop;
+
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
if (! table)
@@ -1579,6 +1687,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
rib->table = vrf_id;
rib->nexthop_num = 0;
rib->uptime = time (NULL);
+ rib->scope = scope;
/* Nexthop settings. */
if (gate)
@@ -1589,12 +1698,18 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, src);
/* If this route is kernel route, set FIB flag to the route. */
- if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
- for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ if (RIB_SYSTEM_ROUTE (rib))
+ {
+ /* Mark system routes with the don't touch me flag */
+ if (! rib_system_routes)
+ SET_FLAG(rib->status, RIB_ENTRY_PRESERVE);
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
/* Link new rib to node.*/
if (IS_ZEBRA_DEBUG_RIB)
@@ -1630,7 +1745,7 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
func,
rib->refcnt,
- rib->uptime,
+ (unsigned long) rib->uptime,
rib->type,
rib->table
);
@@ -1752,8 +1867,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p)
*/
for (rib = rn->info; rib; rib = rib->next)
{
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&
- ! RIB_SYSTEM_ROUTE (rib))
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && RIB_SHOULD_UPDATE (rib))
{
changed = 1;
if (IS_ZEBRA_DEBUG_RIB)
@@ -1767,11 +1881,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p)
}
}
if (changed)
- {
- work_queue_aim_head (zebrad.ribq, 1);
rib_queue_add (&zebrad, rn);
- work_queue_aim_head (zebrad.ribq, 0);
- }
}
int
@@ -2175,8 +2285,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
/* Make new static route structure. */
- si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
- memset (si, 0, sizeof (struct static_ipv4));
+ si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
si->type = type;
si->distance = distance;
@@ -2307,7 +2416,7 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
&& p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
{
- kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+ kernel_delete_ipv6_old (p, gate, ifindex, table);
return 1;
}
return 0;
@@ -2389,12 +2498,18 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
nexthop_ipv6_add (rib, gate);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, NULL);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
- for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ {
+ /* Mark system routes with the don't touch me flag */
+ if (! rib_system_routes)
+ SET_FLAG(rib->status, RIB_ENTRY_PRESERVE);
+
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
/* Link new rib to node.*/
rib_addnode (rn, rib);
@@ -2725,8 +2840,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
}
/* Make new static route structure. */
- si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
- memset (si, 0, sizeof (struct static_ipv6));
+ si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
si->type = type;
si->distance = distance;
@@ -2943,7 +3057,7 @@ rib_close_table (struct route_table *table)
for (rn = route_top (table); rn; rn = route_next (rn))
for (rib = rn->info; rib; rib = rib->next)
{
- if (! RIB_SYSTEM_ROUTE (rib)
+ if (RIB_SHOULD_UPDATE (rib)
&& CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
rib_uninstall_kernel (rn, rib);
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 0c313921..f50ab05e 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -2030,10 +2030,10 @@ static int config_write_protocol(struct vty *vty)
}
/* table node for protocol filtering */
-struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
/* IP node for static routes. */
-struct cmd_node ip_node = { IP_NODE, "", 1 };
+static struct cmd_node ip_node = { IP_NODE, "", 1 };
/* Route VTY. */
void
diff --git a/zebra/zserv.c b/zebra/zserv.c
index ef79eaad..76e74088 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -773,7 +773,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
{
case ZEBRA_NEXTHOP_IFINDEX:
ifindex = stream_getl (s);
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, NULL);
break;
case ZEBRA_NEXTHOP_IFNAME:
ifname_len = stream_getc (s);
@@ -1569,7 +1569,7 @@ config_write_table (struct vty *vty)
}
/* table node for routing tables. */
-struct cmd_node table_node =
+static struct cmd_node table_node =
{
TABLE_NODE,
"", /* This node has no interface. */
@@ -1689,7 +1689,7 @@ config_write_forwarding (struct vty *vty)
}
/* table node for routing tables. */
-struct cmd_node forwarding_node =
+static struct cmd_node forwarding_node =
{
FORWARDING_NODE,
"", /* This node has no interface. */
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 5e223776..87a33a45 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -80,6 +80,7 @@ struct zebra_t
/* rib work queue */
struct work_queue *ribq;
+ struct meta_queue *mq;
};
/* Count prefix size from mask length */