diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/ChangeLog | 30 | ||||
-rw-r--r-- | zebra/Makefile.am | 7 | ||||
-rw-r--r-- | zebra/client_main.c | 2 | ||||
-rw-r--r-- | zebra/connected.c | 35 | ||||
-rw-r--r-- | zebra/connected.h | 4 | ||||
-rw-r--r-- | zebra/if_linkdetect.c | 92 | ||||
-rw-r--r-- | zebra/interface.c | 16 | ||||
-rw-r--r-- | zebra/interface.h | 17 | ||||
-rw-r--r-- | zebra/ioctl.c | 37 | ||||
-rw-r--r-- | zebra/kernel_null.c | 6 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 2 | ||||
-rw-r--r-- | zebra/linkdetect_null.c | 28 | ||||
-rw-r--r-- | zebra/main.c | 15 | ||||
-rw-r--r-- | zebra/rib.h | 25 | ||||
-rw-r--r-- | zebra/rt.h | 4 | ||||
-rw-r--r-- | zebra/rt_ioctl.c | 4 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 318 | ||||
-rw-r--r-- | zebra/rt_socket.c | 4 | ||||
-rw-r--r-- | zebra/rtadv.c | 12 | ||||
-rw-r--r-- | zebra/zebra.conf.sample | 2 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 322 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 4 | ||||
-rw-r--r-- | zebra/zserv.c | 6 | ||||
-rw-r--r-- | zebra/zserv.h | 1 |
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 *); @@ -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 */ |