From 5c78b3d006e6926f938796cffa08e8e14fb8e7af Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 25 Jan 2006 04:31:40 +0000 Subject: [zebra/solaris] Interface state fixups for Solaris. 2006-01-25 Paul Jakma * (general) More solaris PF_ROUTE hacks. The IFF_UP mangling for solaris was incomplete on the PF_ROUTE side. fix it. This changeset generally uglifies things. For some future work I'd like to see the state changes seperated out from the details of the code. Differences between systems might then be slightly easier to implement without convoluted hacks. Changes should be specific to Solaris mostly, however also tested on FreeBSD 6. * if_ioctl_solaris.c: (interface_list_ioctl) ignore ~IFF_UP interfaces, we'll hear about them when/if interface goes up through NEWADDR. Update flags explicitely at end of it to kick mangling. * ioctl_solaris.c: (if_mangle_up) removed to interface.c, in kind. (lifreq_set_name) more convenient to take the string, than the ifp. (if_get_flags_direct) new convenience function, returns the actual flags. Used during bootstrap in if_ioctl_solaris.c to peek at flags of logical interfaces to see whether or not to ignore them. (if_get_flags) ENXIO means it's gone, poke out IFF_UP and kick flags update. (if_{un,}set_flags) flags argument should be 64bit. * ioctl.{c,h}: flags argument should be 64bit. * interface.h: Add a 'primary_state' flag to struct zebra_if on SUNOS_5. Export if_flags_update. * interface.c: (if_flags_mangle) moved over in kind from ioctl_solaris.c. Nasty kludge to try get IFF_UP right, as much as is possible. Also keep track of the actual IFF_UP value for the primary interface, so we can know when the ifp must be deleted. (if_flags_update) Take a new interface flags value, apply it to the interface, and take whatever actions are required due to flag transitions. (if_refresh) flag state change logic is moved out to previous. Just call if_get_flags, which will end up using previous to effect the update of flags. (if_flag_dump_vty) IFF_IPV{4,6} aren't interesting, VIRTUAL and NOXMIT are though. * kernel_socket.c: (ifm_read) Down->Down transitions shouldn't create ifp, for non-IFANNOUNCE systems. Use if_flags_update to update flags. flag transition logic is now handled automatically through if_flags_update. (ifam_read) Better to call if_refresh *after* adding connected addresses, as connected count affects IFF_UP on IFF_UP-mangled systems. On Solaris, Up->Down due to DELADDR means we need to delete the ifp - the IFINFO might already have been and gone. * rt.h: include other dependent headers. --- zebra/kernel_socket.c | 76 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 29 deletions(-) (limited to 'zebra/kernel_socket.c') diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index ae19ef8fe..9764cbb37 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -396,6 +396,14 @@ ifm_read (struct if_msghdr *ifm) ifm->ifm_index); return -1; } + +#ifndef RTM_IFANNOUNCE + /* Down->Down interface should be ignored here. + * See further comment below. + */ + if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP)) + return 0; +#endif /* !RTM_IFANNOUNCE */ if (ifp == NULL) { @@ -414,7 +422,7 @@ ifm_read (struct if_msghdr *ifm) * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; - ifp->flags = ifm->ifm_flags; + if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else @@ -441,34 +449,26 @@ ifm_read (struct if_msghdr *ifm) return -1; } - if (if_is_up (ifp)) - { - ifp->flags = ifm->ifm_flags; - if (! if_is_up (ifp)) - { - if_down (ifp); + /* update flags and handle operative->inoperative transition, if any */ + if_flags_update (ifp, ifm->ifm_flags); + #ifndef RTM_IFANNOUNCE - /* No RTM_IFANNOUNCE on this platform, so we can never - * distinguish between down and delete. We must presume - * it has been deleted. - * Eg, Solaris will not notify us of unplumb. - * - * XXX: Fixme - this should be runtime detected - * So that a binary compiled on a system with IFANNOUNCE - * will still behave correctly if run on a platform without - */ - if_delete_update (ifp); + if (!if_is_up (ifp)) + { + /* No RTM_IFANNOUNCE on this platform, so we can never + * distinguish between ~IFF_UP and delete. We must presume + * it has been deleted. + * Eg, Solaris will not notify us of unplumb. + * + * XXX: Fixme - this should be runtime detected + * So that a binary compiled on a system with IFANNOUNCE + * will still behave correctly if run on a platform without + */ + if_delete_update (ifp); + } #endif /* RTM_IFANNOUNCE */ - } - } - else - { - ifp->flags = ifm->ifm_flags; - if (if_is_up (ifp)) - if_up (ifp); - } } - + #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ @@ -546,9 +546,6 @@ ifam_read (struct ifa_msghdr *ifam) ifp->metric = ifam->ifam_metric; - /* Check interface flag for implicit up of the interface. */ - if_refresh (ifp); - /* Add connected address. */ switch (sockunion_family (&addr)) { @@ -587,6 +584,27 @@ ifam_read (struct ifa_msghdr *ifam) /* Unsupported family silently ignore... */ break; } + + /* Check interface flag for implicit up of the interface. */ + if_refresh (ifp); + +#ifdef SUNOS_5 + /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. + * See comments for SUNOS_5 in interface.c::if_flags_mangle. + * + * Here we take care of case where the real IFF_UP was previously + * unset (as kept in struct zebra_if.primary_state) and the mangled + * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned + * to unset due to the lost non-primary address having DELADDR'd. + * + * we must delete the interface, because in between here and next + * event for this interface-name the administrator could unplumb + * and replumb the interface. + */ + if (!if_is_up (ifp)) + if_delete_update (ifp); +#endif /* SUNOS_5 */ + return 0; } -- cgit v1.2.3