summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/if.h7
-rw-r--r--zebra/connected.c9
-rw-r--r--zebra/interface.c19
3 files changed, 29 insertions, 6 deletions
diff --git a/lib/if.h b/lib/if.h
index 2116e12e..13cc254e 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -151,11 +151,16 @@ struct connected
u_char conf;
#define ZEBRA_IFC_REAL (1 << 0)
#define ZEBRA_IFC_CONFIGURED (1 << 1)
+#define ZEBRA_IFC_QUEUED (1 << 2)
/*
The ZEBRA_IFC_REAL flag should be set if and only if this address
- exists in the kernel.
+ exists in the kernel and is actually usable. (A case where it exists but
+ is not yet usable would be IPv6 with DAD)
The ZEBRA_IFC_CONFIGURED flag should be set if and only if this address
was configured by the user from inside quagga.
+ The ZEBRA_IFC_QUEUED flag should be set if and only if the address exists
+ in the kernel. It may and should be set although the address might not be
+ usable yet. (compare with ZEBRA_IFC_REAL)
*/
/* Flags for connected address. */
diff --git a/zebra/connected.c b/zebra/connected.c
index 38ab37d5..d474560c 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -62,6 +62,9 @@ connected_withdraw (struct connected *ifc)
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
}
+ /* The address is not in the kernel anymore, so clear the flag */
+ UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+
if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
{
listnode_delete (ifc->ifp->connected, ifc);
@@ -211,6 +214,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
ifc = connected_new ();
ifc->ifp = ifp;
ifc->flags = flags;
+ /* If we get a notification from the kernel,
+ * we can safely assume the address is known to the kernel */
+ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
/* Allocate new connected address. */
p = prefix_ipv4_new ();
@@ -363,6 +369,9 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
ifc = connected_new ();
ifc->ifp = ifp;
ifc->flags = flags;
+ /* If we get a notification from the kernel,
+ * we can safely assume the address is known to the kernel */
+ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
/* Allocate new connected address. */
p = prefix_ipv6_new ();
diff --git a/zebra/interface.c b/zebra/interface.c
index cd78ebbc..470df0cd 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -289,7 +289,7 @@ if_addr_wakeup (struct interface *ifp)
p = ifc->address;
if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)
- && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED))
{
/* Address check. */
if (p->family == AF_INET)
@@ -321,6 +321,7 @@ if_addr_wakeup (struct interface *ifp)
/* Add to subnet chain list. */
if_subnet_add (ifp, ifc);
+ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
zebra_interface_address_add_update (ifp, ifc);
@@ -345,6 +346,7 @@ if_addr_wakeup (struct interface *ifp)
safe_strerror(errno));
continue;
}
+ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
zebra_interface_address_add_update (ifp, ifc);
@@ -454,6 +456,7 @@ if_delete_update (struct interface *ifp)
zebra_interface_address_delete_update (ifp, ifc);
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
/* Remove from subnet chain. */
list_delete_node (addr_list, anode);
@@ -482,6 +485,7 @@ if_delete_update (struct interface *ifp)
zebra_interface_address_delete_update (ifp, ifc);
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
last = node;
@@ -1229,7 +1233,7 @@ ip_address_install (struct vty *vty, struct interface *ifp,
SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
&& CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
/* Some system need to up the interface to set IP address. */
@@ -1251,6 +1255,7 @@ ip_address_install (struct vty *vty, struct interface *ifp,
if_subnet_add (ifp, ifc);
/* IP address propery set. */
+ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
/* Update interface address information to protocol daemon. */
@@ -1296,7 +1301,7 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
/* This is not real address or interface is not active. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
|| ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
listnode_delete (ifp->connected, ifc);
@@ -1321,6 +1326,7 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
* through the route socket, and we don't want to touch that behaviour
* for now. It should work without the #ifdef, but why take the risk...
* -- equinox 2012-07-13 */
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
#ifdef HAVE_NETLINK
/* Remove connected route. */
@@ -1437,7 +1443,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
/* In case of this route need to install kernel. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
&& CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
/* Some system need to up the interface to set IP address. */
@@ -1457,6 +1463,7 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
}
/* IP address propery set. */
+ SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
/* Update interface address information to protocol daemon. */
@@ -1502,7 +1509,7 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
/* This is not real address or interface is not active. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
|| ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
listnode_delete (ifp->connected, ifc);
@@ -1519,6 +1526,8 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
return CMD_WARNING;
}
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+
/* Redistribute this information. */
zebra_interface_address_delete_update (ifp, ifc);