diff --git a/src/core/allsta.c b/src/core/allsta.c
index f108e1452d93f95da5442f8f5ad60cbf65aa6d2d..f577f4aa9f14f910132929f5ab5145f966d5402d 100644
--- a/src/core/allsta.c
+++ b/src/core/allsta.c
@@ -15,6 +15,7 @@
 #include <easy/easy.h>
 #include "utils.h"
 #include "debug.h"
+#include "hlist.h"
 #include "allsta.h"
 
 /* hash table of all active stas in the network */
diff --git a/src/core/cntlr.c b/src/core/cntlr.c
index 11ea70575b6ff1cfb7e1a985a0a02f70566449cb..423edf98f71c4cb2434e6b6a2ce358c5a2c80deb 100644
--- a/src/core/cntlr.c
+++ b/src/core/cntlr.c
@@ -41,6 +41,7 @@
 #include "config.h"
 #include "cntlr.h"
 #include "comm.h"
+#include "hlist.h"
 #include "allsta.h"
 #include "cntlr_ubus.h"
 #include "cntlr_map.h"
diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c
index 2b5d3c23fa47bd64549288cca6898fb116ee146e..1420c25554756b971834e920c4d06c25a8f770ce 100644
--- a/src/core/cntlr_ubus.c
+++ b/src/core/cntlr_ubus.c
@@ -31,6 +31,7 @@
 #include "debug.h"
 #include "config.h"
 #include "cntlr.h"
+#include "hlist.h"
 #include "allsta.h"
 #include "cntlr_map.h"
 #include "cntlr_ubus.h"
diff --git a/src/utils/hlist.h b/src/utils/hlist.h
new file mode 100644
index 0000000000000000000000000000000000000000..faf0078901eff2767896608ed87df8e4fceb131e
--- /dev/null
+++ b/src/utils/hlist.h
@@ -0,0 +1,101 @@
+/*
+ * hlist.h - stripped down version of hash list implementation using
+ * singly linked list.
+ * Doubly linked list is wastage of space for big hash-tables. If cost of
+ * iterating a hash list is significant, it means the hash function is NOT
+ * formulated well and should be revisited.
+ *
+ * Copyright (C) 2019 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: anjan.chanda@iopsys.eu
+ *
+ */
+
+#ifndef _HLIST_H
+#define _HLIST_H
+
+struct hlist_node {
+	struct hlist_node *next;
+};
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+#define HLIST_HEAD_INIT(name) { &(name) }
+
+#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT(name)
+
+static inline void INIT_HLIST_HEAD(struct hlist_head *h)
+{
+	h->first = NULL;
+}
+
+static inline void INIT_HLIST_NODE(struct hlist_node *n)
+{
+	n->next = NULL;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *prev, struct hlist_node *n)
+{
+	prev->next = n->next;
+	n->next = NULL;
+}
+
+static inline void hlist_del(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *p;
+
+	if (h->first == n) {
+		h->first = NULL;
+		n->next = NULL;
+		return;
+	}
+
+	for (p = h->first; p; p = p->next) {
+		if (p->next == n)
+			__hlist_del(p, n);
+	}
+}
+
+static inline void _hlist_add(struct hlist_node *_new, struct hlist_head *h)
+{
+	_new->next = h->first;
+	h->first = _new;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	_hlist_add(n, h);
+}
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos ; pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define hlist_entry_safe(ptr, type, member) \
+	({ typeof(ptr) ____ptr = (ptr); \
+	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+	})
+
+#define hlist_for_each_entry(pos, head, member)                                \
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);    \
+	     pos;                                                              \
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_safe(pos, n, head, member)                   \
+	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member); \
+	     pos && ({ n = pos->member.next; 1; });                       \
+	     pos = hlist_entry_safe(n, typeof(*pos), member))
+
+#endif /* _HLIST_H */