* is used to look up any existing instances that match the interface. It does
* not matter whether the instance is already bound to the interface or not.
*
+ * Note that the interface linkages must be correct for this to work. In other
+ * words, the macvlan must have a valid VRRP MAC, and its link_ifindex must be
+ * be equal to the ifindex of another interface in the interface RB trees (its
+ * parent). If these conditions aren't satisfied we won't find the VR.
+ *
* mvl_ifp
* Interface pointer to use to lookup. Should be a macvlan device.
*
r->vr->vrid, family2str(r->family),
vrrp_event_names[VRRP_EVENT_SHUTDOWN],
vrrp_state_names[VRRP_STATE_INITIALIZE]);
- break;
+ return 0;
}
/* Cancel all timers */
{
struct listnode *ln;
struct vrrp_vrouter *vr;
- struct list *vrs = vrrp_lookup_by_if_any(ifp);
vrrp_if_down(ifp);
+ /*
+ * You think we'd be able use vrrp_lookup_by_if_any to find interfaces?
+ * Nah. FRR's interface management is insane. There are no ordering
+ * guarantees about what interfaces are deleted when. Maybe this is a
+ * macvlan and its parent was already deleted, in which case its
+ * ifindex is now IFINDEX_INTERNAL, so ifp->link_ifindex - while still
+ * valid - doesn't match any interface on the system, meaning we can't
+ * use any of the vrrp_lookup* functions since they rely on finding the
+ * base interface of what they're given by following link_ifindex.
+ *
+ * Since we need to actually NULL out pointers in this function to
+ * avoid a UAF - since the caller will (might) free ifp after we return
+ * - we need to look up based on pointers.
+ */
+ struct list *vrs = hash_to_list(vrrp_vrouters_hash);
+
for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
- if (vr->v4->mvl_ifp == ifp || vr->ifp == ifp) {
+ if (ifp == vr->ifp) {
+ vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+ vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
/*
- * If either of our interfaces goes away, we need to
- * down the session
+ * Stands to reason if the base was deleted, so were
+ * (or will be) its children
*/
- if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
- vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
-
+ vr->v4->mvl_ifp = NULL;
+ vr->v6->mvl_ifp = NULL;
/*
- * If it was the macvlan, then it wasn't explicitly
- * configured and will be deleted when we return from
- * this function, so we need to lose the reference
+ * We shouldn't need to lose the reference if it's the
+ * primary interface, because that was configured
+ * explicitly in our config, and thus will be kept as a
+ * stub; to avoid stupid bugs, double check that
*/
- if (ifp == vr->v4->mvl_ifp)
- vr->v4->mvl_ifp = NULL;
-
- } else if (vr->v6->mvl_ifp == ifp || vr->ifp == ifp) {
+ assert(ifp->configured);
+ } else if (ifp == vr->v4->mvl_ifp) {
+ vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
/*
- * If either of our interfaces goes away, we need to
- * down the session
+ * If this is a macvlan, then it wasn't explicitly
+ * configured and will be deleted when we return from
+ * this function, so we need to lose the reference
*/
- if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE)
- vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
-
+ vr->v4->mvl_ifp = NULL;
+ } else if (ifp == vr->v6->mvl_ifp) {
+ vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
/*
- * If it was the macvlan, then it wasn't explicitly
+ * If this is a macvlan, then it wasn't explicitly
* configured and will be deleted when we return from
* this function, so we need to lose the reference
*/
- if (ifp == vr->v6->mvl_ifp)
- vr->v6->mvl_ifp = NULL;
+ vr->v6->mvl_ifp = NULL;
}
-
- /*
- * We shouldn't need to lose the reference if it's the primary
- * interface, because that was configured explicitly in our
- * config, and thus will be kept as a stub; to avoid stupid
- * bugs, double check that
- */
- if (ifp == vr->ifp)
- assert(ifp->configured);
}
list_delete(&vrs);