diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/connected.c | 38 | ||||
-rw-r--r-- | zebra/connected.h | 4 | ||||
-rw-r--r-- | zebra/if_netlink.c | 5 | ||||
-rw-r--r-- | zebra/interface.c | 83 | ||||
-rw-r--r-- | zebra/interface.h | 13 | ||||
-rw-r--r-- | zebra/irdp_interface.c | 5 | ||||
-rw-r--r-- | zebra/irdp_packet.c | 2 | ||||
-rw-r--r-- | zebra/kernel_null.c | 6 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 4 | ||||
-rw-r--r-- | zebra/main.c | 12 | ||||
-rw-r--r-- | zebra/redistribute.c | 10 | ||||
-rw-r--r-- | zebra/rib.h | 73 | ||||
-rw-r--r-- | zebra/rt.h | 4 | ||||
-rw-r--r-- | zebra/rt_ioctl.c | 4 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 400 | ||||
-rw-r--r-- | zebra/rt_socket.c | 4 | ||||
-rw-r--r-- | zebra/rtadv.c | 82 | ||||
-rw-r--r-- | zebra/rtadv.h | 2 | ||||
-rw-r--r-- | zebra/rtread_getmsg.c | 2 | ||||
-rw-r--r-- | zebra/rtread_netlink.c | 6 | ||||
-rw-r--r-- | zebra/rtread_proc.c | 3 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 497 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 128 | ||||
-rw-r--r-- | zebra/zserv.c | 6 | ||||
-rw-r--r-- | zebra/zserv.h | 2 |
25 files changed, 895 insertions, 500 deletions
diff --git a/zebra/connected.c b/zebra/connected.c index ad3e9607..80cb8cbc 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -36,23 +36,31 @@ #include "zebra/interface.h" #include "zebra/connected.h" extern struct zebra_t zebrad; + /* withdraw a connected address */ static void connected_withdraw (struct connected *ifc) { + if (! ifc) return; /* Update interface address information to protocol daemon. */ if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { + int count; + zebra_interface_address_delete_update (ifc->ifp, ifc); - if_subnet_delete (ifc->ifp, ifc); + count = if_subnet_delete (ifc->ifp, ifc); if (ifc->address->family == AF_INET) + { connected_down_ipv4 (ifc->ifp, ifc); + if (count == 0) + rib_flush_interface (AFI_IP, ifc->ifp); + } #ifdef HAVE_IPV6 else connected_down_ipv6 (ifc->ifp, ifc); @@ -86,7 +94,7 @@ connected_announce (struct interface *ifp, struct connected *ifc) zebra_interface_address_add_update (ifp, ifc); - if (if_is_up(ifp)) + if (if_is_operative(ifp)) { if (ifc->address->family == AF_INET) connected_up_ipv4 (ifp, ifc); @@ -174,6 +182,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,14 +197,15 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) if (prefix_ipv4_any (&p)) return; - rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - RT_TABLE_MAIN, ifp->metric, 0); + rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, &src, + ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0, + RT_SCOPE_LINK, RTPROT_KERNEL); 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) @@ -270,10 +280,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 @@ -318,6 +328,8 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, return; connected_withdraw (ifc); + + rib_update(); } #ifdef HAVE_IPV6 @@ -347,7 +359,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) } /* 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) @@ -394,10 +406,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 @@ -437,5 +449,7 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, return; connected_withdraw (ifc); + + rib_update(); } #endif /* HAVE_IPV6 */ 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_netlink.c b/zebra/if_netlink.c index c9c14760..701c81b6 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -22,12 +22,11 @@ #include <zebra.h> -/* Extern from rt_netlink.c */ -void interface_lookup_netlink (); +extern int interface_lookup_netlink (void); /* Interface information read by netlink. */ void -interface_list () +interface_list (void) { interface_lookup_netlink (); } diff --git a/zebra/interface.c b/zebra/interface.c index 184b42a0..c096d611 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -41,6 +41,11 @@ #include "zebra/debug.h" #include "zebra/irdp.h" +#ifdef RTADV +/* Order is intentional. Matches RFC4191. This array is also used for + command matching, so only modify with care. */ +const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 }; +#endif /* RTADV */ /* Called when new interface is added. */ static int @@ -48,8 +53,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; @@ -76,6 +80,7 @@ if_zebra_new_hook (struct interface *ifp) rtadv->HomeAgentPreference = 0; rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME; rtadv->AdvIntervalOption = 0; + rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new (); } @@ -103,6 +108,7 @@ if_zebra_delete_hook (struct interface *ifp) route_table_finish (zebra_if->ipv4_subnets); XFREE (MTYPE_TMP, zebra_if); + ifp->info = NULL; } return 0; @@ -484,6 +490,54 @@ if_delete_update (struct interface *ifp) ifp->ifindex = IFINDEX_INTERNAL; } +/* Interfaces can only be renamed when DOWN */ +void +if_rename (struct interface *ifp, const char *name) +{ + struct interface *oifp; + + UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + zebra_interface_delete_update (ifp); + listnode_delete (iflist, ifp); + + /* rename overlaps earlier interface */ + oifp = if_lookup_by_name(name); + if (oifp) + { + ifp->status |= oifp->status; /* inherit config bits */ + if (oifp->ifindex != IFINDEX_INTERNAL) + { + zlog_err ("interface %s rename to %s overlaps with index %d", + ifp->name, name, oifp->ifindex); + if_delete_update (oifp); + } + else if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("interface %s index %d superseded by rename of %s", + oifp->name, oifp->ifindex, ifp->name); + + listnode_delete (iflist, oifp); + XFREE (MTYPE_IF, oifp); + } + + strncpy(ifp->name, name, INTERFACE_NAMSIZ); + ifp->name[INTERFACE_NAMSIZ] = 0; + listnode_add_sort (iflist, ifp); + + zebra_interface_add_update (ifp); + + SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); + + if (ifp->connected) + { + struct connected *ifc; + struct listnode *node; + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) + zebra_interface_address_add_update (ifp, ifc); + } + + rib_update(); +} + /* Interface is up. */ void if_up (struct interface *ifp) @@ -538,15 +592,25 @@ if_down (struct interface *ifp) if (p->family == AF_INET) connected_down_ipv4 (ifp, ifc); + } + } + + /* Examine all static routes which direct to the interface. */ + rib_update (); + #ifdef HAVE_IPV6 - else if (p->family == AF_INET6) + if (ifp->connected) + { + for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc)) + { + p = ifc->address; + if (p->family == AF_INET6) connected_down_ipv6 (ifp, ifc); -#endif /* HAVE_IPV6 */ } } - /* Examine all static routes which direct to the interface. */ rib_update (); +#endif /* HAVE_IPV6 */ } void @@ -623,6 +687,9 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) VTY_NEWLINE); vty_out (vty, " ND router advertisements live for %d seconds%s", rtadv->AdvDefaultLifetime, VTY_NEWLINE); + vty_out (vty, " ND router advertisement default router preference is " + "%s%s", rtadv_pref_strs[rtadv->DefaultPreference], + VTY_NEWLINE); if (rtadv->AdvManagedFlag) vty_out (vty, " Hosts use DHCP to obtain routable addresses.%s", VTY_NEWLINE); @@ -822,6 +889,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp) #endif /* HAVE_NET_RT_IFLIST */ } +#if 0 /* Check supported address family. */ static int if_supported_family (int family) @@ -834,6 +902,7 @@ if_supported_family (int family) #endif /* HAVE_IPV6 */ return 0; } +#endif /* Wrapper hook point for zebra daemon so that ifindex can be set * DEFUN macro not used as extract.pl HAS to ignore this @@ -1514,7 +1583,6 @@ if_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; - char buf[BUFSIZ]; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { @@ -1544,10 +1612,11 @@ if_config_write (struct vty *vty) { if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) { + char buf[INET6_ADDRSTRLEN]; p = ifc->address; vty_out (vty, " ip%s address %s/%d", p->family == AF_INET ? "" : "v6", - inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)), p->prefixlen); if (ifc->label) diff --git a/zebra/interface.h b/zebra/interface.h index 0a6b0365..827729a3 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -46,7 +46,7 @@ #endif #ifdef RTADV -/* Router advertisement parameter. From RFC2461 and RFC3775. */ +/* Router advertisement parameter. From RFC2461, RFC3775 and RFC4191. */ struct rtadvconf { /* A flag indicating whether or not the router sends periodic Router @@ -171,6 +171,13 @@ struct rtadvconf Default: FALSE */ int AdvIntervalOption; + + /* The value to be placed in the Default Router Preference field of + a router advertisement. See [RFC 4191 2.1 & 2.2] + + Default: 0 (medium) */ + int DefaultPreference; +#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ }; #endif /* RTADV */ @@ -187,9 +194,6 @@ struct zebra_if /* Router advertise configuration. */ u_char rtadv_enable; - /* Interface's address. */ - struct list *address; - /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; @@ -215,6 +219,7 @@ extern void if_delete_update (struct interface *ifp); extern void if_add_update (struct interface *ifp); extern void if_up (struct interface *); extern void if_down (struct interface *); +extern void if_rename (struct interface *, const char *); extern void if_refresh (struct interface *); extern void if_flags_update (struct interface *, uint64_t); extern int if_subnet_add (struct interface *, struct connected *); diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index dd773402..b3a838b3 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -175,10 +175,7 @@ if_set_defaults(struct interface *ifp) struct Adv *Adv_new (void) { - struct Adv *new; - new = XMALLOC (MTYPE_TMP, sizeof (struct Adv)); - memset (new, 0, sizeof (struct Adv)); - return new; + return XCALLOC (MTYPE_TMP, sizeof (struct Adv)); } static void diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 3c5f1559..ae121ea1 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -231,7 +231,7 @@ int irdp_read_raw(struct thread *r) struct zebra_if *zi; struct irdp_interface *irdp; char buf[IRDP_RX_BUF]; - int ret, ifindex; + int ret, ifindex = 0; int irdp_sock = THREAD_FD (r); t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock); 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 e77b9b78..dc298687 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -161,7 +161,7 @@ const struct message rtm_type_str[] = {0, NULL} }; -struct message rtm_flag_str[] = +static const struct message rtm_flag_str[] = { {RTF_UP, "UP"}, {RTF_GATEWAY, "GATEWAY"}, @@ -898,7 +898,7 @@ rtm_read (struct rt_msghdr *rtm) || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0); + &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, 0, 0); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0); diff --git a/zebra/main.c b/zebra/main.c index 61750f1d..209b9044 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 connected routes */ +extern int set_interface_mode; + /* Command line options. */ struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, { "keep_kernel", no_argument, NULL, 'k'}, + { "set_interface", 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': + set_interface_mode = 1; + break; case 'C': dryrun = 1; break; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index b7bd5674..a8107aeb 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -369,13 +369,14 @@ zebra_interface_address_add_update (struct interface *ifp, struct listnode *node, *nnode; struct zserv *client; struct prefix *p; - char buf[BUFSIZ]; if (IS_ZEBRA_DEBUG_EVENT) { + char buf[INET6_ADDRSTRLEN]; + p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", - inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, ifc->ifp->name); } @@ -394,13 +395,14 @@ zebra_interface_address_delete_update (struct interface *ifp, struct listnode *node, *nnode; struct zserv *client; struct prefix *p; - char buf[BUFSIZ]; if (IS_ZEBRA_DEBUG_EVENT) { + char buf[INET6_ADDRSTRLEN]; + p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", - inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, ifc->ifp->name); } diff --git a/zebra/rib.h b/zebra/rib.h index 887ed3c2..c374df37 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -38,10 +38,6 @@ union g_addr { struct rib { - /* Status Flags for the *route_node*, but kept in the head RIB.. */ - u_char rn_status; -#define RIB_ROUTE_QUEUED(x) (1 << (x)) - /* Link list. */ struct rib *next; struct rib *prev; @@ -49,20 +45,30 @@ struct rib /* Nexthop structure */ struct nexthop *nexthop; - /* Refrence count. */ + /* Reference count. */ unsigned long refcnt; /* Uptime. */ time_t uptime; - /* Type fo this route. */ - int type; + /* Metric */ + u_int32_t metric; /* Which routing table */ - int table; + u_int32_t table; - /* Metric */ - u_int32_t metric; + /* Type for this route. < ZEBRA_ROUTE_MAX */ + u_int8_t type; + + /* Scope for this route: RTM_UNIVERSE .. RTM_NOWHERE */ + u_int8_t scope; + + /* Routing protocol: RTPROT_UNSPEC .. */ + u_int8_t protocol; + + /* Status Flags for the *route_node*, but kept in the head RIB.. */ + u_char rn_status; +#define RIB_ROUTE_QUEUED(x) (1 << (x)) /* Distance. */ u_char distance; @@ -104,6 +110,13 @@ struct static_ipv4 struct static_ipv4 *prev; struct static_ipv4 *next; + /* Nexthop value. */ + union + { + struct in_addr ipv4; + char *ifname; + } gate; + /* Administrative distance. */ u_char distance; @@ -113,13 +126,6 @@ struct static_ipv4 #define STATIC_IPV4_IFNAME 2 #define STATIC_IPV4_BLACKHOLE 3 - /* Nexthop value. */ - union - { - struct in_addr ipv4; - char *ifname; - } gate; - /* bit flags */ u_char flags; /* @@ -136,6 +142,10 @@ struct static_ipv6 struct static_ipv6 *prev; struct static_ipv6 *next; + /* Nexthop value. */ + struct in6_addr ipv6; + char *ifname; + /* Administrative distance. */ u_char distance; @@ -144,11 +154,6 @@ struct static_ipv6 #define STATIC_IPV6_GATEWAY 1 #define STATIC_IPV6_GATEWAY_IFNAME 2 #define STATIC_IPV6_IFNAME 3 - - /* Nexthop value. */ - struct in6_addr ipv6; - char *ifname; - /* bit flags */ u_char flags; /* @@ -180,22 +185,24 @@ struct nexthop /* Interface index. */ char *ifname; unsigned int ifindex; + + /* Nexthop address or interface name. */ + union g_addr gate; + + unsigned int rifindex; + union g_addr rgate; + union g_addr src; - enum nexthop_types_t type; +/* Really enum nexthop_types_t but safe space */ + u_char type; u_char flags; #define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */ #define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */ #define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */ - /* Nexthop address or interface name. */ - union g_addr gate; - /* Recursive lookup nexthop. */ u_char rtype; - unsigned int rifindex; - union g_addr rgate; - union g_addr src; }; /* Routing table instance. */ @@ -220,7 +227,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 *, @@ -249,7 +257,8 @@ 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, u_int8_t protocol); extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *); @@ -264,6 +273,8 @@ extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); extern void rib_update (void); extern void rib_weed_tables (void); extern void rib_sweep_route (void); +struct interface; +extern void rib_flush_interface (afi_t afi, struct interface *ifp); extern void rib_close (void); extern void rib_init (void); @@ -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 05254498..2cff4c8c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -85,32 +85,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 set_interface_mode; - 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_up(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) @@ -280,7 +259,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), while (1) { - char buf[4096]; + char buf[32768]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; @@ -311,6 +290,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 ( NULL, LOG_ERR, "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)) { @@ -462,14 +448,23 @@ 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->ifindex = ifi->ifi_index; 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. */ @@ -523,7 +518,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) @@ -539,6 +534,9 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp = if_lookup_by_index (ifa->ifa_index); if (ifp == NULL) { + if (h->nlmsg_type == RTM_DELADDR) + return 0; + zlog_err ("netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; @@ -548,7 +546,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]), @@ -614,9 +612,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 (set_interface_mode && 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, @@ -626,9 +640,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, @@ -652,7 +666,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) int index; int table; - int metric; + u_int32_t metric; void *dest; void *gate; @@ -682,6 +696,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; + if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; @@ -699,7 +714,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]); @@ -714,7 +729,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) { @@ -723,7 +738,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, rtm->rtm_protocol); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) @@ -768,6 +784,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) int index; int table; + u_int32_t metric; + void *dest; void *gate; void *src; @@ -781,33 +799,35 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) return 0; } + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); + if (len < 0) + return -1; + + memset (tb, 0, sizeof tb); + netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); + + if (tb[RTA_DST]) + dest = RTA_DATA (tb[RTA_DST]); + else + dest = anyaddr; + /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s %s %s proto %s", - h->nlmsg_type == - RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", - rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", - rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", - lookup (rtproto_str, rtm->rtm_protocol)); + { + char buf[INET6_ADDRSTRLEN]; + zlog_debug ("%s %s %s proto %s", + h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", + inet_ntop(rtm->rtm_family, dest, buf, sizeof(buf)), + rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", + lookup (rtproto_str, rtm->rtm_protocol)); + } if (rtm->rtm_type != RTN_UNICAST) - { return 0; - } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default) - { return 0; - } - - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); - if (len < 0) - return -1; - - memset (tb, 0, sizeof tb); - netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); - if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) @@ -825,17 +845,12 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } index = 0; - dest = NULL; + metric = 0; gate = NULL; src = NULL; if (tb[RTA_OIF]) - index = *(int *) RTA_DATA (tb[RTA_OIF]); - - if (tb[RTA_DST]) - dest = RTA_DATA (tb[RTA_DST]); - else - dest = anyaddr; + index = *(uint32_t *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); @@ -843,6 +858,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); + if (tb[RTA_PRIORITY]) + metric = *(uint32_t *) RTA_DATA(tb[RTA_PRIORITY]); + if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; @@ -850,18 +868,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; - if (IS_ZEBRA_DEBUG_KERNEL) - { - if (h->nlmsg_type == RTM_NEWROUTE) - zlog_debug ("RTM_NEWROUTE %s/%d", - inet_ntoa (p.prefix), p.prefixlen); - else - zlog_debug ("RTM_DELROUTE %s/%d", - inet_ntoa (p.prefix), p.prefixlen); - } - 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, + metric, 0, rtm->rtm_scope, rtm->rtm_protocol); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); } @@ -870,26 +879,13 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; - char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; - if (IS_ZEBRA_DEBUG_KERNEL) - { - if (h->nlmsg_type == RTM_NEWROUTE) - zlog_debug ("RTM_NEWROUTE %s/%d", - inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), - p.prefixlen); - else - zlog_debug ("RTM_DELROUTE %s/%d", - inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), - p.prefixlen); - } - if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, metric, 0); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0); } @@ -919,7 +915,10 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) - return -1; + { + zlog_err ("%s: truncated netlink message", __func__); + return -1; + } /* Looking up interface name. */ memset (tb, 0, sizeof tb); @@ -936,62 +935,96 @@ 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) { - ifp = if_lookup_by_name (name); + unsigned long new_flags = ifi->ifi_flags & 0x0000fffff; + unsigned int mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug ("%s: new link flags %#lx mtu %d", __func__, new_flags, mtu); + ifp = if_lookup_by_index (ifi->ifi_index); if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) - ifp = if_get_by_name (name); + { + ifp = if_get_by_name (name); + ifp->ifindex = ifi->ifi_index; + ifp->metric = 1; + } + + 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 = ifi->ifi_flags & 0x0000fffff; - ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); - ifp->metric = 1; + ifp->flags = new_flags; + ifp->mtu6 = ifp->mtu = mtu; /* 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; - - if (if_is_operative (ifp)) - { - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (!if_is_operative (ifp)) - if_down (ifp); + /* Interface status change. */ + else if (new_flags != ifp->flags) + { + ifp->mtu6 = ifp->mtu = mtu; + + 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); - } - else - { - ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_operative (ifp)) - if_up (ifp); - } - } + 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); + + if_rename (ifp, name); + } + /* Interface mtu change */ + else if (mtu != ifp->mtu) + { + zlog_info("interface %s mtu changed from %u to %u", + ifp->name, 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); - + // RTM_DELLINK. + 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 + zlog_info ("interface %s index %d deleted.", + name, ifi->ifi_index); if_delete_update (ifp); } @@ -1002,13 +1035,6 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) static int netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) { - /* JF: Ignore messages that aren't from the kernel */ - if ( snl->nl_pid != 0 ) - { - zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid ); - return 0; - } - switch (h->nlmsg_type) { case RTM_NEWROUTE: @@ -1188,11 +1214,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"); @@ -1217,15 +1238,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; @@ -1235,59 +1252,26 @@ 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_table = table; req.r.rtm_dst_len = length; - req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - - if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE) - || (zebra_flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) - { - 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; - } + req.r.rtm_scope = RT_SCOPE_NOWHERE; + req.r.rtm_protocol = RTPROT_UNSPEC; + req.r.rtm_table = table; 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. */ @@ -1318,14 +1302,24 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, req.r.rtm_family = family; req.r.rtm_table = rib->table; req.r.rtm_dst_len = p->prefixlen; - req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_scope = rib->scope; if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; + switch (rib->type) { + case ZEBRA_ROUTE_KERNEL: + req.r.rtm_protocol = rib->protocol; + break; + case ZEBRA_ROUTE_CONNECT: + req.r.rtm_protocol = RTPROT_KERNEL; + break; + default: + req.r.rtm_protocol = RTPROT_ZEBRA; + } + if (cmd == RTM_NEWROUTE) { if (discard) @@ -1343,8 +1337,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) { @@ -1743,12 +1737,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 */ @@ -1837,19 +1831,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), }; 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 4bdb83d5..0feb850a 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -84,17 +84,16 @@ 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 static void rtadv_free (struct rtadv *rtadv) { XFREE (MTYPE_TMP, rtadv); } +#endif static int rtadv_recv_packet (int sock, u_char *buf, int buflen, @@ -209,7 +208,12 @@ rtadv_send_packet (int sock, struct interface *ifp) rtadv->nd_ra_cksum = 0; rtadv->nd_ra_curhoplimit = 64; - rtadv->nd_ra_flags_reserved = 0; + + /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */ + rtadv->nd_ra_flags_reserved = + zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference; + rtadv->nd_ra_flags_reserved <<= 3; + if (zif->rtadv.AdvManagedFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; if (zif->rtadv.AdvOtherConfigFlag) @@ -451,7 +455,7 @@ rtadv_read (struct thread *thread) int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; - unsigned int ifindex; + unsigned int ifindex = 0; int hoplimit = -1; sock = THREAD_FD (thread); @@ -527,14 +531,9 @@ rtadv_make_socket (void) } static struct rtadv_prefix * -rtadv_prefix_new () +rtadv_prefix_new (void) { - 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 @@ -1372,6 +1371,56 @@ DEFUN (no_ipv6_nd_prefix, return CMD_SUCCESS; } + +DEFUN (ipv6_nd_router_preference, + ipv6_nd_router_preference_cmd, + "ipv6 nd router-preference (high|medium|low)", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Default router preference\n" + "High default router preference\n" + "Low default router preference\n" + "Medium default router preference (default)\n") +{ + struct interface *ifp; + struct zebra_if *zif; + int i = 0; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + while (0 != rtadv_pref_strs[i]) + { + if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0) + { + zif->rtadv.DefaultPreference = i; + return CMD_SUCCESS; + } + i++; + } + + return CMD_ERR_NO_MATCH; +} + +DEFUN (no_ipv6_nd_router_preference, + no_ipv6_nd_router_preference_cmd, + "no ipv6 nd router-preference", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Default router preference\n") +{ + struct interface *ifp; + struct zebra_if *zif; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */ + + return CMD_SUCCESS; +} + /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) @@ -1419,6 +1468,11 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) if (zif->rtadv.AdvOtherConfigFlag) vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE); + if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM) + vty_out (vty, " ipv6 nd router-preference %s%s", + rtadv_pref_strs[zif->rtadv.DefaultPreference], + VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { vty_out (vty, " ipv6 nd prefix %s/%d", @@ -1540,6 +1594,8 @@ rtadv_init (void) install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd); + install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); } static int diff --git a/zebra/rtadv.h b/zebra/rtadv.h index abd1c6fc..d8d263d0 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -94,4 +94,6 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +extern const char *rtadv_pref_strs[]; + #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 3e065c6f..2978ae11 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -90,7 +90,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry) gateway.s_addr = routeEntry->ipRouteNextHop; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, - &gateway, NULL, 0, 0, 0, 0); + &gateway, NULL, 0, 0, 0, 0, 0, 0); } void diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 0b255a53..44715d94 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -21,11 +21,9 @@ */ #include <zebra.h> +extern void netlink_route_read (void); -/* Extern from rt_netlink.c */ -void netlink_route_read (); - -void route_read () +void route_read (void) { netlink_route_read (); } diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c index 1de435a4..4f246de9 100644 --- a/zebra/rtread_proc.c +++ b/zebra/rtread_proc.c @@ -96,7 +96,8 @@ proc_route_read (void) p.prefixlen = ip_masklen (tmpmask); sscanf (gate, "%lX", (unsigned long *)&gateway); - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, + 0, 0, 0, 0, 0, 0); } fclose (fp); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 90db932b..ade13578 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 set_interface_mode; + /* 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. @@ -93,6 +96,7 @@ vrf_alloc (const char *name) return vrf; } +#if 0 /* Free VRF. */ static void vrf_free (struct vrf *vrf) @@ -101,6 +105,7 @@ vrf_free (struct vrf *vrf) XFREE (MTYPE_VRF_NAME, vrf->name); XFREE (MTYPE_VRF, vrf); } +#endif /* Lookup VRF by identifier. */ struct vrf * @@ -109,6 +114,7 @@ vrf_lookup (u_int32_t id) return vector_lookup (vrf_vector, id); } +#if 0 /* Lookup VRF by name. */ static struct vrf * vrf_lookup_by_name (char *name) @@ -122,6 +128,7 @@ vrf_lookup_by_name (char *name) return vrf; return NULL; } +#endif /* Initialize VRF. */ static void @@ -205,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); @@ -224,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); @@ -239,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) @@ -257,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) @@ -276,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; @@ -292,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); @@ -309,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; @@ -326,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); @@ -336,6 +338,35 @@ nexthop_blackhole_add (struct rib *rib) return nexthop; } +static int +nexthop_isactive(const struct nexthop *nexthop) +{ + struct interface *ifp; + + switch(nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + if (nexthop->ifindex == 0) + return 0; + /* fall through */ + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + ifp = if_lookup_by_index (nexthop->ifindex); + return (ifp && if_is_operative (ifp)); + + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV4_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + ifp = if_lookup_by_name(nexthop->ifname); + return (ifp && if_is_operative (ifp)); + + default: + return 1; + } +} + /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static int @@ -348,11 +379,12 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, struct rib *match; struct nexthop *newhop; - if (nexthop->type == NEXTHOP_TYPE_IPV4) - nexthop->ifindex = 0; - if (set) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + { + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + if (nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = 0; + } /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); @@ -400,16 +432,31 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, { /* Directly point connected route. */ newhop = match->nexthop; - if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4) - nexthop->ifindex = newhop->ifindex; - - return 1; + if (!newhop) + return 0; /* dead route */ + + if (nexthop_isactive (newhop)) + { + if (set) + { + if (nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = newhop->ifindex; + } + else + { + if (nexthop->ifindex != newhop->ifindex || + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } + return 1; + } } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) - && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE) + && nexthop_isactive (newhop)) { if (set) { @@ -422,7 +469,24 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, || newhop->type == NEXTHOP_TYPE_IFNAME || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) nexthop->rifindex = newhop->ifindex; + if (nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = newhop->ifindex; + } + else if (! CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) + || nexthop->rtype != newhop->type + || ((newhop->type == NEXTHOP_TYPE_IPV4 || + newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) && + nexthop->gate.ipv4.s_addr != newhop->gate.ipv4.s_addr) + || ((newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) && + nexthop->rifindex != newhop->ifindex) + || ((nexthop->type == NEXTHOP_TYPE_IPV4) && + nexthop->ifindex != newhop->ifindex)) + { + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); } + return 1; } return 0; @@ -501,17 +565,35 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, { /* Directly point connected route. */ newhop = match->nexthop; + if (!newhop) + return 0; /* dead route */ - if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6) + /* recursive route, remember index */ + if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = newhop->ifindex; - return 1; + if (nexthop_isactive (newhop)) + { + if (set) + { + if (nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = newhop->ifindex; + } + else + { + if (nexthop->ifindex != newhop->ifindex || + CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } + return 1; + } } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) - && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE) + && nexthop_isactive (newhop)) { if (set) { @@ -526,7 +608,27 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) nexthop->rifindex = newhop->ifindex; + if (nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = newhop->ifindex; + } + else if (! CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) + || nexthop->rtype != newhop->type + || ((newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) && + !IPV6_ADDR_SAME (&nexthop->rgate.ipv6, + &newhop->gate.ipv6)) + || ((newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) && + nexthop->rifindex != newhop->ifindex) + || ((nexthop->type == NEXTHOP_TYPE_IPV6) && + (nexthop->ifindex != newhop->ifindex))) + { + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); } + return 1; } return 0; @@ -700,24 +802,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; } @@ -786,9 +888,18 @@ 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) +static inline int rib_is_managed(const struct rib *rib) +{ + switch (rib->type) { + case ZEBRA_ROUTE_KERNEL: return 0; + case ZEBRA_ROUTE_CONNECT: return set_interface_mode; + default: return 1; + } +} + /* This function verifies reachability of one given nexthop, which can be * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored * in nexthop->flags field. If the 4th parameter, 'set', is non-zero, @@ -798,7 +909,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) @@ -971,8 +1081,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 */ @@ -991,7 +1099,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_is_managed (rib)) rib_uninstall_kernel (rn, rib); UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); } @@ -1111,22 +1219,23 @@ rib_process (struct route_node *rn) if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", - __func__, buf, rn->p.prefixlen, select, fib); + zlog_debug ("%s: %s/%d: Updating existing route, fib %p flags %#x status %#x", + __func__, buf, rn->p.prefixlen, fib, + (unsigned) select->flags, (unsigned) select->status); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { redistribute_delete (&rn->p, select); - if (! RIB_SYSTEM_ROUTE (select)) + if (rib_is_managed (select)) rib_uninstall_kernel (rn, select); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); - if (! RIB_SYSTEM_ROUTE (select)) + if (rib_is_managed (select)) rib_install_kernel (rn, select); redistribute_add (&rn->p, select); } - else if (! RIB_SYSTEM_ROUTE (select)) + else if (rib_is_managed (select)) { /* Housekeeping code to deal with race conditions in kernel with linux @@ -1157,7 +1266,7 @@ rib_process (struct route_node *rn) 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_is_managed (fib)) rib_uninstall_kernel (rn, fib); UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); @@ -1177,7 +1286,7 @@ rib_process (struct route_node *rn) /* Set real nexthop. */ nexthop_active_update (rn, select, 1); - if (! RIB_SYSTEM_ROUTE (select)) + if (rib_is_managed (select)) rib_install_kernel (rn, select); SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); redistribute_add (&rn->p, select); @@ -1197,21 +1306,26 @@ end: zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); } -/* 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. + +/* 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; + struct listnode *lnode = listhead (subq); struct route_node *rnode; - if (!(lnode = listhead (subq))) + + 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; @@ -1225,66 +1339,66 @@ static wq_item_status meta_queue_process (struct work_queue *dummy, void *data) { struct meta_queue * mq = data; - u_char i; + unsigned i; + for (i = 0; i < MQ_SIZE; i++) if (process_subq (mq->subq[i], i)) - { - mq->size--; - break; - } + { + mq->size--; + break; + } return mq->size ? WQ_REQUEUE : WQ_SUCCESS; } -/* Look into the RN and queue it into one or more priority queues, increasing the size - * for each data push done. +/* 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) { - u_char qindex; 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) - { - switch (rib->type) - { - case ZEBRA_ROUTE_KERNEL: - case ZEBRA_ROUTE_CONNECT: - qindex = 0; - break; - case ZEBRA_ROUTE_STATIC: - qindex = 1; - break; - case ZEBRA_ROUTE_RIP: - case ZEBRA_ROUTE_RIPNG: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_ISIS: - qindex = 2; - break; - case ZEBRA_ROUTE_BGP: - qindex = 3; - break; - default: - qindex = 4; - break; - } - /* Invariant: at this point we always have rn->info set. */ - if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex))) { + 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: 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); - } + 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 */ @@ -1336,27 +1450,24 @@ 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. */ +/* 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, failed = 0; + unsigned i; + + new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue)); + assert(new); - if ((new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue))) == NULL) - return NULL; for (i = 0; i < MQ_SIZE; i++) - if ((new->subq[i] = list_new ()) == NULL) - failed = 1; - if (failed) - { - for (i = 0; i < MQ_SIZE; i++) - if (new->subq[i]) - list_delete (new->subq[i]); - XFREE (MTYPE_WORK_QUEUE, new); - return NULL; - } - new->size = 0; + { + new->subq[i] = list_new (); + assert(new->subq[i]); + } + return new; } @@ -1542,7 +1653,8 @@ 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, u_int8_t proto) { struct rib *rib; struct rib *same = NULL; @@ -1550,6 +1662,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) @@ -1598,6 +1711,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Allocate new rib structure. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + rib->type = type; rib->distance = distance; rib->flags = flags; @@ -1605,6 +1719,8 @@ 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; + rib->protocol = proto; /* Nexthop settings. */ if (gate) @@ -1615,12 +1731,12 @@ 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); + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); /* Link new rib to node.*/ if (IS_ZEBRA_DEBUG_RIB) @@ -1653,10 +1769,10 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen); zlog_debug ( - "%s: refcnt == %lu, uptime == %u, type == %u, table == %d", + "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", func, rib->refcnt, - rib->uptime, + (unsigned long) rib->uptime, rib->type, rib->table ); @@ -1778,8 +1894,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_is_managed (rib)) { changed = 1; if (IS_ZEBRA_DEBUG_RIB) @@ -1878,8 +1993,8 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct rib *fib = NULL; struct rib *same = NULL; struct nexthop *nexthop; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); @@ -1891,11 +2006,18 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (IS_ZEBRA_DEBUG_KERNEL && gate) zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, inet_ntoa (*gate), ifindex); + if (IS_ZEBRA_DEBUG_KERNEL && !gate) + zlog_debug ("rib_delete_ipv4(): route delete %s/%d directly, %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex2ifname(ifindex), + ifindex); + /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); if (! rn) @@ -1904,13 +2026,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, { if (gate) zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, - inet_ntop (AF_INET, gate, buf2, BUFSIZ), + inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, ifindex); } @@ -1942,7 +2064,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, break; } /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || + else if (gate != NULL && ((nexthop = rib->nexthop) && (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) @@ -1970,14 +2092,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, { if (gate) zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, - inet_ntop (AF_INET, gate, buf2, BUFSIZ), + inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, ifindex, type); @@ -2197,8 +2319,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; @@ -2239,6 +2360,9 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, /* Install into rib. */ static_install_ipv4 (p, si); + /* Scan for possible recursive route changes */ + rib_update(); + return 1; } @@ -2303,6 +2427,9 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, route_unlock_node (rn); + /* Scan for possible recursive route changes */ + rib_update(); + return 1; } @@ -2323,7 +2450,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; @@ -2405,7 +2532,7 @@ 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) @@ -2434,8 +2561,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct rib *fib = NULL; struct rib *same = NULL; struct nexthop *nexthop; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; + char buf1[INET6_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; /* Apply mask. */ apply_mask_ipv6 (p); @@ -2453,13 +2580,13 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, { if (gate) zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, - inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, ifindex); } @@ -2519,14 +2646,14 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, { if (gate) zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, - inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, ifindex, type); @@ -2741,8 +2868,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; @@ -2785,6 +2911,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, /* Install into rib. */ static_install_ipv6 (p, si); + /* Scan for possible recursive route changes */ + rib_update(); return 1; } @@ -2838,6 +2966,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, XFREE (0, si->ifname); XFREE (MTYPE_STATIC_IPV6, si); + rib_update(); return 1; } #endif /* HAVE_IPV6 */ @@ -2862,6 +2991,7 @@ rib_update (void) rib_queue_add (&zebrad, rn); } +#if 0 /* Interface goes up. */ static void rib_if_up (struct interface *ifp) @@ -2875,6 +3005,7 @@ rib_if_down (struct interface *ifp) { rib_update (); } +#endif /* Remove all routes which comes from non main table. */ static void @@ -2942,6 +3073,66 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } + +/* When all IPV4 subnets are gone on Linux, the kernel frees all routes */ +void +rib_flush_interface(afi_t afi, struct interface *ifp) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib, *next; + + table = vrf_table(afi, SAFI_UNICAST, 0); + if (!table) + return; + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: flushing references to %s", __func__, ifp->name); + + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + struct nexthop *nexthop; + + next = rib->next; + + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + switch(rib->type) { + case ZEBRA_ROUTE_KERNEL: + if ( (nexthop = rib->nexthop) && + (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || + nexthop->type == NEXTHOP_TYPE_IFINDEX) && + nexthop->ifindex == ifp->ifindex) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: calling rib_delnode (%p, %p) on kernel RIB entry", + __func__, rn, rib); + rib_delnode(rn, rib); + } + break; + + case ZEBRA_ROUTE_STATIC: + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + switch(nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (nexthop->ifindex == ifp->ifindex) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + break; + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV4_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + if (strcmp(nexthop->ifname, ifp->name) == 0) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + } +} /* Close RIB and clean up kernel routes. */ static void @@ -2954,7 +3145,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_is_managed (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..d4e3a4ae 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -87,6 +87,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, return CMD_SUCCESS; } + /* Mark static routes as internal so they get evaluated as recursive */ + SET_FLAG (flag, ZEBRA_FLAG_INTERNAL); + /* Route flags */ if (flag_str) { switch(flag_str[0]) { @@ -1057,29 +1060,65 @@ DEFUN (show_ip_route_prefix, } static void -zebra_show_ip_route (struct vty *vty, struct vrf *vrf) +vty_show_ip_route_summary (struct vty *vty, struct route_table *table) { - vty_out (vty, "IP routing table name is %s(%d)%s", - vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE); - - vty_out (vty, "Route Source Networks%s", VTY_NEWLINE); - vty_out (vty, "connected %d%s", 0, VTY_NEWLINE); - vty_out (vty, "static %d%s", 0, VTY_NEWLINE); - vty_out (vty, "rip %d%s", 0, VTY_NEWLINE); - - vty_out (vty, "bgp %d%s", 0, VTY_NEWLINE); - vty_out (vty, " External: %d Internal: %d Local: %d%s", - 0, 0, 0, VTY_NEWLINE); - - vty_out (vty, "ospf %d%s", 0, VTY_NEWLINE); - vty_out (vty, - " Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s", - 0, 0, 0, 0, VTY_NEWLINE); - vty_out (vty, " NSSA External-1: %d NSSA External-2: %d%s", - 0, 0, VTY_NEWLINE); - - vty_out (vty, "internal %d%s", 0, VTY_NEWLINE); - vty_out (vty, "Total %d%s", 0, VTY_NEWLINE); + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; +#define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX +#define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1) + u_int32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1]; + u_int32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1]; + u_int32_t i; + + memset (&rib_cnt, 0, sizeof(rib_cnt)); + memset (&fib_cnt, 0, sizeof(fib_cnt)); + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + rib_cnt[ZEBRA_ROUTE_TOTAL]++; + rib_cnt[rib->type]++; + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + fib_cnt[ZEBRA_ROUTE_TOTAL]++; + fib_cnt[rib->type]++; + } + if (rib->type == ZEBRA_ROUTE_BGP && + CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) + { + rib_cnt[ZEBRA_ROUTE_IBGP]++; + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + fib_cnt[ZEBRA_ROUTE_IBGP]++; + } + } + + vty_out (vty, "%-20s %-20s %-20s %s", + "Route Source", "Routes", "FIB", VTY_NEWLINE); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + { + if (rib_cnt[i] > 0) + { + if (i == ZEBRA_ROUTE_BGP) + { + vty_out (vty, "%-20s %-20d %-20d %s", "ebgp", + rib_cnt[ZEBRA_ROUTE_BGP] - rib_cnt[ZEBRA_ROUTE_IBGP], + fib_cnt[ZEBRA_ROUTE_BGP] - fib_cnt[ZEBRA_ROUTE_IBGP], + VTY_NEWLINE); + vty_out (vty, "%-20s %-20d %-20d %s", "ibgp", + rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_IBGP], + VTY_NEWLINE); + } + else + vty_out (vty, "%-20s %-20d %-20d %s", zebra_route_string(i), + rib_cnt[i], fib_cnt[i], VTY_NEWLINE); + } + } + + vty_out (vty, "------%s", VTY_NEWLINE); + vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL], + fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE); } /* Show route summary. */ @@ -1091,17 +1130,13 @@ DEFUN (show_ip_route_summary, "IP routing table\n" "Summary of all routes\n") { - struct vrf *vrf; + struct route_table *table; - /* Default table id is zero. */ - vrf = vrf_lookup (0); - if (! vrf) - { - vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE); - return CMD_WARNING; - } + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; - zebra_show_ip_route (vty, vrf); + vty_show_ip_route_summary (vty, table); return CMD_SUCCESS; } @@ -1943,6 +1978,26 @@ DEFUN (show_ipv6_route_prefix, return CMD_SUCCESS; } +/* Show route summary. */ +DEFUN (show_ipv6_route_summary, + show_ipv6_route_summary_cmd, + "show ipv6 route summary", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "Summary of all IPv6 routes\n") +{ + struct route_table *table; + + table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + if (! table) + return CMD_SUCCESS; + + vty_show_ip_route_summary (vty, table); + + return CMD_SUCCESS; +} + /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) @@ -2030,10 +2085,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 @@ -2076,17 +2131,14 @@ zebra_vty_init (void) install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_route_protocol_cmd); install_element (VIEW_NODE, &show_ip_route_supernets_cmd); + install_element (VIEW_NODE, &show_ip_route_summary_cmd); install_element (ENABLE_NODE, &show_ip_route_cmd); install_element (ENABLE_NODE, &show_ip_route_addr_cmd); install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_route_protocol_cmd); install_element (ENABLE_NODE, &show_ip_route_supernets_cmd); - -#if 0 - install_element (VIEW_NODE, &show_ip_route_summary_cmd); install_element (ENABLE_NODE, &show_ip_route_summary_cmd); -#endif /* 0 */ #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); @@ -2106,6 +2158,7 @@ zebra_vty_init (void) install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd); install_element (VIEW_NODE, &show_ipv6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_route_summary_cmd); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); install_element (VIEW_NODE, &show_ipv6_route_addr_cmd); install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); @@ -2115,5 +2168,6 @@ zebra_vty_init (void) install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd); install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd); #endif /* HAVE_IPV6 */ } 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 87a33a45..1171b619 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -76,7 +76,7 @@ struct zebra_t struct list *client_list; /* default table */ - int rtm_table_default; + u_int32_t rtm_table_default; /* rib work queue */ struct work_queue *ribq; |