Index: common/include/adt/hash.h
===================================================================
--- common/include/adt/hash.h	(revision 8f8818ace0c872218dd0662d192937ee82aa966f)
+++ common/include/adt/hash.h	(revision 93de3843ffaa4f5998c74e2074d88a32d88800e2)
@@ -108,3 +108,40 @@
 }
 
+/** Hash a NUL-terminated string.
+ * The algorithm may change in the future, so never use it for hashes
+ * that will be stored to a file or sent over a network.
+ */
+static inline size_t hash_string(const char *str)
+{
+	/* djb2 hash + extra mixing at the end */
+
+	char c;
+	size_t hash = 5381;
+
+	while ((c = *(str++)))
+		hash = (hash << 5) + hash + c;
+
+	return hash_mix(hash);
+}
+
+/** Hash an arbitrarily sized sequence of bytes.
+ * The algorithm may change in the future, so never use it for hashes
+ * that will be stored to a file or sent over a network.
+ */
+static inline size_t hash_bytes(const void *b, size_t len)
+{
+	/* djb2 hash + extra mixing at the end */
+
+	// TODO: work in bigger chunks for faster hashing
+
+	const char *str = b;
+
+	size_t hash = 5381;
+
+	for (size_t i = 0; i < len; i++)
+		hash = (hash << 5) + hash + str[i];
+
+	return hash_mix(hash);
+}
+
 #endif
Index: common/include/adt/hash_table.h
===================================================================
--- common/include/adt/hash_table.h	(revision 8f8818ace0c872218dd0662d192937ee82aa966f)
+++ common/include/adt/hash_table.h	(revision 93de3843ffaa4f5998c74e2074d88a32d88800e2)
@@ -60,5 +60,5 @@
 
 	/** Returns true if the key is equal to the item's lookup key. */
-	bool (*key_equal)(const void *key, const ht_link_t *item);
+	bool (*key_equal)(const void *key, size_t hash, const ht_link_t *item);
 
 	/** Hash table item removal callback.
@@ -85,4 +85,11 @@
 	member_to_inst((item), type, member)
 
+#define hash_table_foreach(ht, key, member, itype, iterator) \
+	for (itype *iterator = NULL; \
+	    iterator == NULL; iterator = (itype *) INTPTR_MAX) \
+		for (ht_link_t *__link = hash_table_find((ht), (key)); \
+		    __link != NULL && ((iterator = member_to_inst(__link, itype, member))); \
+			__link = hash_table_find_next((ht), __link))
+
 extern bool hash_table_create(hash_table_t *, size_t, size_t,
     const hash_table_ops_t *);
@@ -96,6 +103,5 @@
 extern bool hash_table_insert_unique(hash_table_t *, ht_link_t *);
 extern ht_link_t *hash_table_find(const hash_table_t *, const void *);
-extern ht_link_t *hash_table_find_next(const hash_table_t *, ht_link_t *,
-    ht_link_t *);
+extern ht_link_t *hash_table_find_next(const hash_table_t *, ht_link_t *);
 extern size_t hash_table_remove(hash_table_t *, const void *);
 extern void hash_table_remove_item(hash_table_t *, ht_link_t *);
