summaryrefslogtreecommitdiff
path: root/zebra/connected.c
diff options
context:
space:
mode:
authorPaul Jakma <paul.jakma@sun.com>2006-06-15 18:10:47 +0000
committerPaul Jakma <paul.jakma@sun.com>2006-06-15 18:10:47 +0000
commit74ecdc9e74eb96829e342a03531ba6647ce6bb3c (patch)
treef40b1ba761f9ad9271c1951510bbd63eeaa57961 /zebra/connected.c
parent630c97ce0f87a719f678a24bd84945d4f145fdc5 (diff)
[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.
Diffstat (limited to 'zebra/connected.c')
-rw-r--r--zebra/connected.c83
1 files changed, 62 insertions, 21 deletions
diff --git a/zebra/connected.c b/zebra/connected.c
index 37aa456a..736b40b0 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -111,6 +111,63 @@ connected_check (struct interface *ifp, struct prefix *p)
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 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
{
struct prefix_ipv4 *p;
struct connected *ifc;
- struct connected *current;
/* Make connected structure. */
ifc = connected_new ();
@@ -226,16 +282,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
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 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
{
struct prefix_ipv6 *p;
struct connected *ifc;
- struct connected *current;
/* Make connected structure. */
ifc = connected_new ();
@@ -373,15 +421,8 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
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);
}