#define ZEBRA_IFC_REAL (1 << 0)
#define ZEBRA_IFC_CONFIGURED (1 << 1)
#define ZEBRA_IFC_QUEUED (1 << 2)
+#define ZEBRA_IFC_DOWN (1 << 3)
/*
The ZEBRA_IFC_REAL flag should be set if and only if this address
exists in the kernel and is actually usable. (A case where it exists
in the kernel. It may and should be set although the address might
not be
usable yet. (compare with ZEBRA_IFC_REAL)
+ The ZEBRA_IFC_DOWN flag is used to record that an address is
+ present, but down/unavailable.
*/
/* Flags for connected address. */
#include "zebra/connected.h"
#include "zebra/rtadv.h"
#include "zebra/zebra_mpls.h"
-#include "zebra/debug.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
+ /* Ensure 'down' flag is cleared */
+ UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
+
PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
/* Apply mask to the network. */
PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
apply_mask(&cp);
- if (prefix_same(&cp, &p))
+ if (prefix_same(&cp, &p) &&
+ !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
count++;
if (count >= 2)
if (!zvrf) {
flog_err(
EC_ZEBRA_VRF_NOT_FOUND,
- "%s: Received Up for interface but no associated zvrf: %d",
+ "%s: Received Down for interface but no associated zvrf: %d",
__func__, ifp->vrf_id);
return;
}
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
return;
+ /* Skip if we've already done this; this can happen if we have a
+ * config change that takes an interface down, then we receive kernel
+ * notifications about the downed interface and its addresses.
+ */
+ if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_DOWN)) {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: ifc %p, %pFX already DOWN",
+ __func__, ifc, ifc->address);
+ return;
+ }
+
PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
/* Apply mask to the network. */
break;
}
+ /* Mark the address as 'down' */
+ SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
+
/*
* It's possible to have X number of addresses
* on a interface that all resolve to the same
PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
apply_mask(&cp);
- if (prefix_same(&p, &cp))
+ if (prefix_same(&p, &cp) &&
+ !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
count++;
- if (count >= 2)
+ if (count >= 1)
return;
}