+#endif /* __linux__ */
+
+static struct numa_node *
+insert_new_numa_node(int numa_id)
+{
+ struct numa_node *n = xzalloc(sizeof *n);
+
+ hmap_insert(&all_numa_nodes, &n->hmap_node, hash_int(numa_id, 0));
+ ovs_list_init(&n->cores);
+ n->numa_id = numa_id;
+
+ return n;
+}
+
+static struct cpu_core *
+insert_new_cpu_core(struct numa_node *n, unsigned core_id)
+{
+ struct cpu_core *c = xzalloc(sizeof *c);
+
+ hmap_insert(&all_cpu_cores, &c->hmap_node, hash_int(core_id, 0));
+ ovs_list_insert(&n->cores, &c->list_node);
+ c->core_id = core_id;
+ c->numa = n;
+ c->available = true;
+
+ return c;
+}
+
+/* Has the same effect as discover_numa_and_core(), but instead of reading
+ * sysfs entries, extracts the info from 'dummy_config'.
+ *
+ * 'dummy_config' lists the numa_ids of each CPU separated by a comma, e.g.
+ * - "0,0,0,0": four cores on numa socket 0.
+ * - "0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1": 16 cores on two numa sockets.
+ * - "0,0,0,0,1,1,1,1": 8 cores on two numa sockets.
+ *
+ * The different numa ids must be consecutives or the function will abort. */
+static void
+discover_numa_and_core_dummy(const char *dummy_config)
+{
+ char *conf = xstrdup(dummy_config);
+ char *id, *saveptr = NULL;
+ unsigned i = 0;
+ long max_numa_id = 0;
+
+ for (id = strtok_r(conf, ",", &saveptr); id;
+ id = strtok_r(NULL, ",", &saveptr)) {
+ struct hmap_node *hnode;
+ struct numa_node *n;
+ long numa_id;
+
+ numa_id = strtol(id, NULL, 10);
+ if (numa_id < 0 || numa_id >= MAX_NUMA_NODES) {
+ VLOG_WARN("Invalid numa node %ld", numa_id);
+ continue;
+ }
+
+ max_numa_id = MAX(max_numa_id, numa_id);
+
+ hnode = hmap_first_with_hash(&all_numa_nodes, hash_int(numa_id, 0));
+
+ if (hnode) {
+ n = CONTAINER_OF(hnode, struct numa_node, hmap_node);
+ } else {
+ n = insert_new_numa_node(numa_id);
+ }
+
+ insert_new_cpu_core(n, i);
+
+ i++;
+ }
+
+ free(conf);
+
+ if (max_numa_id + 1 != hmap_count(&all_numa_nodes)) {
+ ovs_fatal(0, "dummy numa contains non consecutive numa ids");
+ }
+}