+ static long long int last = 0;
+ long long int now = time_msec();
+
+ /* Do maintenance at most 4 times / sec. */
+ ovs_mutex_lock(&mutex);
+ if (now - last > 250) {
+ struct recirc_id_node *node;
+
+ last = now;
+
+ /* Nodes in 'expiring' and 'expired' lists have the refcount of zero,
+ * which means that while they can still be found (by id), no new
+ * references can be taken on them. We have removed the entry from the
+ * 'metadata_map', at the time when refcount reached zero, causing any
+ * new translations to allocate a new ID. This allows the expiring
+ * entry to be safely deleted while any sudden new use of the similar
+ * recirculation will safely start using a new recirculation ID. When
+ * the refcount gets to zero, the node is also added to the 'expiring'
+ * list. At any time after that the nodes in the 'expiring' list can
+ * be moved to the 'expired' list, from which they are deleted at least
+ * 250ms afterwards. */
+
+ /* Delete the expired. These have been lingering for at least 250 ms,
+ * which should be enough for any ongoing recirculations to be
+ * finished. */
+ LIST_FOR_EACH_POP (node, exp_node, &expired) {
+ cmap_remove(&id_map, &node->id_node, node->id);
+ ovsrcu_postpone(recirc_id_node_free, node);
+ }
+
+ if (!list_is_empty(&expiring)) {
+ /* 'expired' is now empty, move nodes in 'expiring' to it. */
+ list_splice(&expired, list_front(&expiring), &expiring);
+ }
+ }
+ ovs_mutex_unlock(&mutex);