};
#define VXLAN_SGRP_F_DELETE BIT(0)
+#define VXLAN_SGRP_F_NEW BIT(1)
struct vxlan_mdb_src_entry {
struct hlist_node node;
ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr);
if (!ent)
return -ENOMEM;
+ ent->flags |= VXLAN_SGRP_F_NEW;
} else if (!(cfg->nlflags & NLM_F_REPLACE)) {
NL_SET_ERR_MSG_MOD(extack, "Source entry already exists");
return -EEXIST;
if (err)
goto err_src_del;
- /* Clear flags in case source entry was marked for deletion as part of
- * replace flow.
+ /* Clear the deletion mark so the entry survives the replace sweep.
+ * The new mark is retained until the whole operation succeeds.
*/
- ent->flags = 0;
+ ent->flags &= ~VXLAN_SGRP_F_DELETE;
return 0;
err_src_del:
- vxlan_mdb_remote_src_entry_del(ent);
+ if (ent->flags & VXLAN_SGRP_F_NEW)
+ vxlan_mdb_remote_src_entry_del(ent);
return err;
}
goto err_src_del;
}
+ hlist_for_each_entry(ent, &remote->src_list, node)
+ ent->flags &= ~VXLAN_SGRP_F_NEW;
+
return 0;
err_src_del:
- hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node)
- vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent);
+ hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
+ if (ent->flags & VXLAN_SGRP_F_NEW)
+ vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote,
+ ent);
+ else
+ ent->flags &= ~VXLAN_SGRP_F_DELETE;
+ }
return err;
}
err = vxlan_mdb_remote_srcs_add(cfg, remote, extack);
if (err)
- goto err_clear_delete;
+ return err;
hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
if (ent->flags & VXLAN_SGRP_F_DELETE)
}
return 0;
-
-err_clear_delete:
- hlist_for_each_entry(ent, &remote->src_list, node)
- ent->flags &= ~VXLAN_SGRP_F_DELETE;
- return err;
}
static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,