[zebra] Fix forgetfulness wrt configured address on FreeBSD
2006-06-15 Paul Jakma <paul.jakma@sun.com>
* (general) The key fixes are actually Andrew Schorr's.
* interface.c: (ip_address_uninstall) Unset the configured flag.
* connected.c: (connected_same) new helper, check whether
two connected are same.
(connected_implicit_withdraw) new helper, consolidation of
existing code in connected_add_ipv{4,6}.
Try filter out unneeded Zserv address delete/adds when
address is exact same.
Where old address is implicitely removed, be sure to preserve
the IFC_CONFIGURED flag if set, fixes bug where configured
addresses were being lost on FreeBSD.
diff --git a/zebra/connected.c b/zebra/connected.c
index 37aa456..736b40b 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -111,6 +111,63 @@
return NULL;
}
+/* Check if two ifc's describe the same address */
+static int
+connected_same (struct connected *ifc1, struct connected *ifc2)
+{
+ if (ifc1->ifp != ifc2->ifp)
+ return 0;
+
+ if (ifc1->destination)
+ if (!ifc2->destination)
+ return 0;
+ if (ifc2->destination)
+ if (!ifc1->destination)
+ return 0;
+
+ if (ifc1->destination && ifc2->destination)
+ if (!prefix_same (ifc1->destination, ifc2->destination))
+ return 0;
+
+ if (ifc1->flags != ifc2->flags)
+ return 0;
+
+ return 1;
+}
+
+/* Handle implicit withdrawals of addresses, where a system ADDs an address
+ * to an interface which already has the same address configured.
+ *
+ * Returns the struct connected which must be announced to clients,
+ * or NULL if nothing to do.
+ */
+static struct connected *
+connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
+{
+ struct connected *current;
+
+ /* Check same connected route. */
+ if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
+ {
+ if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
+ SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
+
+ /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
+ * back an address we have already added.
+ */
+ if (connected_same (current, ifc))
+ {
+ /* nothing to do */
+ connected_free (ifc);
+ return NULL;
+ }
+
+ UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
+ connected_withdraw (current); /* implicit withdraw - freebsd does this */
+ }
+ return ifc;
+}
+
/* Called from if_up(). */
void
connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
@@ -157,7 +214,6 @@
{
struct prefix_ipv4 *p;
struct connected *ifc;
- struct connected *current;
/* Make connected structure. */
ifc = connected_new ();
@@ -226,16 +282,9 @@
if (label)
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
- /* Check same connected route. */
- if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
- {
- if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
- {
- SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
- UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
- }
- connected_withdraw (current); /* implicit withdraw - freebsd does this */
- }
+ /* nothing to do? */
+ if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
+ return;
connected_announce (ifp, ifc);
}
@@ -347,7 +396,6 @@
{
struct prefix_ipv6 *p;
struct connected *ifc;
- struct connected *current;
/* Make connected structure. */
ifc = connected_new ();
@@ -373,15 +421,8 @@
if (label)
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
- if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
- {
- if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
- {
- SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
- UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
- }
- connected_withdraw (current); /* implicit update of existing address */
- }
+ if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
+ return;
connected_announce (ifp, ifc);
}