summaryrefslogtreecommitdiff
path: root/zebra/kernel_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/kernel_socket.c')
-rw-r--r--zebra/kernel_socket.c76
1 files changed, 47 insertions, 29 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index ae19ef8f..9764cbb3 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;
}