hashtable.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * netlink/hashtable.c Netlink hashtable Utilities
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2012 Cumulus Networks, Inc
  10. */
  11. #include <string.h>
  12. #include <netlink-private/netlink.h>
  13. #include <netlink/object.h>
  14. #include <netlink/hash.h>
  15. #include <netlink/hashtable.h>
  16. /**
  17. * @ingroup core_types
  18. * @defgroup hashtable Hashtable
  19. * @{
  20. */
  21. /**
  22. * Allocate hashtable
  23. * @arg size Size of hashtable in number of elements
  24. *
  25. * @return Allocated hashtable or NULL.
  26. */
  27. nl_hash_table_t *nl_hash_table_alloc(int size)
  28. {
  29. nl_hash_table_t *ht;
  30. ht = calloc(1, sizeof (*ht));
  31. if (!ht)
  32. goto errout;
  33. ht->nodes = calloc(size, sizeof (*ht->nodes));
  34. if (!ht->nodes) {
  35. free(ht);
  36. goto errout;
  37. }
  38. ht->size = size;
  39. return ht;
  40. errout:
  41. return NULL;
  42. }
  43. /**
  44. * Free hashtable including all nodes
  45. * @arg ht Hashtable
  46. *
  47. * @note Reference counter of all objects in the hashtable will be decremented.
  48. */
  49. void nl_hash_table_free(nl_hash_table_t *ht)
  50. {
  51. int i;
  52. for(i = 0; i < ht->size; i++) {
  53. nl_hash_node_t *node = ht->nodes[i];
  54. nl_hash_node_t *saved_node;
  55. while (node) {
  56. saved_node = node;
  57. node = node->next;
  58. nl_object_put(saved_node->obj);
  59. free(saved_node);
  60. }
  61. }
  62. free(ht->nodes);
  63. free(ht);
  64. }
  65. /**
  66. * Lookup identical object in hashtable
  67. * @arg ht Hashtable
  68. * @arg obj Object to lookup
  69. *
  70. * Generates hashkey for `obj` and traverses the corresponding chain calling
  71. * `nl_object_identical()` on each trying to find a match.
  72. *
  73. * @return Pointer to object if match was found or NULL.
  74. */
  75. struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht,
  76. struct nl_object *obj)
  77. {
  78. nl_hash_node_t *node;
  79. uint32_t key_hash;
  80. nl_object_keygen(obj, &key_hash, ht->size);
  81. node = ht->nodes[key_hash];
  82. while (node) {
  83. if (nl_object_identical(node->obj, obj))
  84. return node->obj;
  85. node = node->next;
  86. }
  87. return NULL;
  88. }
  89. /**
  90. * Add object to hashtable
  91. * @arg ht Hashtable
  92. * @arg obj Object to add
  93. *
  94. * Adds `obj` to the hashtable. Object type must support hashing, otherwise all
  95. * objects will be added to the chain `0`.
  96. *
  97. * @note The reference counter of the object is incremented.
  98. *
  99. * @return 0 on success or a negative error code
  100. * @retval -NLE_EXIST Identical object already present in hashtable
  101. */
  102. int nl_hash_table_add(nl_hash_table_t *ht, struct nl_object *obj)
  103. {
  104. nl_hash_node_t *node;
  105. uint32_t key_hash;
  106. nl_object_keygen(obj, &key_hash, ht->size);
  107. node = ht->nodes[key_hash];
  108. while (node) {
  109. if (nl_object_identical(node->obj, obj)) {
  110. NL_DBG(2, "Warning: Add to hashtable found duplicate...\n");
  111. return -NLE_EXIST;
  112. }
  113. node = node->next;
  114. }
  115. NL_DBG (5, "adding cache entry of obj %p in table %p, with hash 0x%x\n",
  116. obj, ht, key_hash);
  117. node = malloc(sizeof(nl_hash_node_t));
  118. if (!node)
  119. return -NLE_NOMEM;
  120. nl_object_get(obj);
  121. node->obj = obj;
  122. node->key = key_hash;
  123. node->key_size = sizeof(uint32_t);
  124. node->next = ht->nodes[key_hash];
  125. ht->nodes[key_hash] = node;
  126. return 0;
  127. }
  128. /**
  129. * Remove object from hashtable
  130. * @arg ht Hashtable
  131. * @arg obj Object to remove
  132. *
  133. * Remove `obj` from hashtable if it exists.
  134. *
  135. * @note Reference counter of object will be decremented.
  136. *
  137. * @return 0 on success or a negative error code.
  138. * @retval -NLE_OBJ_NOTFOUND Object not present in hashtable.
  139. */
  140. int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj)
  141. {
  142. nl_hash_node_t *node, *prev;
  143. uint32_t key_hash;
  144. nl_object_keygen(obj, &key_hash, ht->size);
  145. prev = node = ht->nodes[key_hash];
  146. while (node) {
  147. if (nl_object_identical(node->obj, obj)) {
  148. nl_object_put(obj);
  149. NL_DBG (5, "deleting cache entry of obj %p in table %p, with"
  150. " hash 0x%x\n", obj, ht, key_hash);
  151. if (node == ht->nodes[key_hash])
  152. ht->nodes[key_hash] = node->next;
  153. else
  154. prev->next = node->next;
  155. free(node);
  156. return 0;
  157. }
  158. prev = node;
  159. node = node->next;
  160. }
  161. return -NLE_OBJ_NOTFOUND;
  162. }
  163. uint32_t nl_hash(void *k, size_t length, uint32_t initval)
  164. {
  165. return(__nl_hash(k, length, initval));
  166. }
  167. /** @} */