pktloc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * lib/route/pktloc.c Packet Location Aliasing
  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) 2008-2013 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup tc
  13. * @defgroup pktloc Packet Location Aliasing
  14. * Packet Location Aliasing
  15. *
  16. * The packet location aliasing interface eases the use of offset definitions
  17. * inside packets by allowing them to be referenced by name. Known positions
  18. * of protocol fields are stored in a configuration file and associated with
  19. * a name for later reference. The configuration file is distributed with the
  20. * library and provides a well defined set of definitions for most common
  21. * protocol fields.
  22. *
  23. * @section pktloc_examples Examples
  24. * @par Example 1.1 Looking up a packet location
  25. * @code
  26. * struct rtnl_pktloc *loc;
  27. *
  28. * rtnl_pktloc_lookup("ip.src", &loc);
  29. * @endcode
  30. * @{
  31. */
  32. #include <netlink-private/netlink.h>
  33. #include <netlink-private/tc.h>
  34. #include <netlink/netlink.h>
  35. #include <netlink/utils.h>
  36. #include <netlink/route/pktloc.h>
  37. #include "pktloc_syntax.h"
  38. #include "pktloc_grammar.h"
  39. /** @cond SKIP */
  40. #define PKTLOC_NAME_HT_SIZ 256
  41. static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
  42. /* djb2 */
  43. static unsigned int pktloc_hash(const char *str)
  44. {
  45. unsigned long hash = 5381;
  46. int c;
  47. while ((c = *str++))
  48. hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  49. return hash % PKTLOC_NAME_HT_SIZ;
  50. }
  51. static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result)
  52. {
  53. struct rtnl_pktloc *loc;
  54. int hash;
  55. hash = pktloc_hash(name);
  56. nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
  57. if (!strcasecmp(loc->name, name)) {
  58. loc->refcnt++;
  59. *result = loc;
  60. return 0;
  61. }
  62. }
  63. return -NLE_OBJ_NOTFOUND;
  64. }
  65. extern int pktloc_parse(void *scanner);
  66. static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
  67. {
  68. if (!loc)
  69. return;
  70. free(loc->name);
  71. free(loc);
  72. }
  73. static int read_pktlocs(void)
  74. {
  75. YY_BUFFER_STATE buf = NULL;
  76. yyscan_t scanner = NULL;
  77. static time_t last_read;
  78. struct stat st;
  79. char *path;
  80. int i, err;
  81. FILE *fd;
  82. if (build_sysconf_path(&path, "pktloc") < 0)
  83. return -NLE_NOMEM;
  84. /* if stat fails, just try to read the file */
  85. if (stat(path, &st) == 0) {
  86. /* Don't re-read file if file is unchanged */
  87. if (last_read == st.st_mtime)
  88. return 0;
  89. }
  90. NL_DBG(2, "Reading packet location file \"%s\"\n", path);
  91. if (!(fd = fopen(path, "r"))) {
  92. err = -NLE_PKTLOC_FILE;
  93. goto errout;
  94. }
  95. for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
  96. struct rtnl_pktloc *loc, *n;
  97. nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
  98. rtnl_pktloc_put(loc);
  99. nl_init_list_head(&pktloc_name_ht[i]);
  100. }
  101. if ((err = pktloc_lex_init(&scanner)) < 0) {
  102. err = -NLE_FAILURE;
  103. goto errout_close;
  104. }
  105. buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
  106. pktloc__switch_to_buffer(buf, scanner);
  107. if ((err = pktloc_parse(scanner)) != 0) {
  108. pktloc__delete_buffer(buf, scanner);
  109. err = -NLE_PARSE_ERR;
  110. goto errout_scanner;
  111. }
  112. last_read = st.st_mtime;
  113. errout_scanner:
  114. pktloc_lex_destroy(scanner);
  115. errout_close:
  116. fclose(fd);
  117. errout:
  118. free(path);
  119. return err;
  120. }
  121. /** @endcond */
  122. /**
  123. * Lookup packet location alias
  124. * @arg name Name of packet location.
  125. * @arg result Result pointer
  126. *
  127. * Tries to find a matching packet location alias for the supplied
  128. * packet location name.
  129. *
  130. * The file containing the packet location definitions is automatically
  131. * re-read if its modification time has changed since the last call.
  132. *
  133. * The returned packet location has to be returned after use by calling
  134. * rtnl_pktloc_put() in order to allow freeing its memory after the last
  135. * user has abandoned it.
  136. *
  137. * @return 0 on success or a negative error code.
  138. * @retval NLE_PKTLOC_FILE Unable to open packet location file.
  139. * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
  140. */
  141. int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
  142. {
  143. int err;
  144. if ((err = read_pktlocs()) < 0)
  145. return err;
  146. return __pktloc_lookup(name, result);
  147. }
  148. /**
  149. * Allocate packet location object
  150. */
  151. struct rtnl_pktloc *rtnl_pktloc_alloc(void)
  152. {
  153. struct rtnl_pktloc *loc;
  154. if (!(loc = calloc(1, sizeof(*loc))))
  155. return NULL;
  156. loc->refcnt = 1;
  157. nl_init_list_head(&loc->list);
  158. return loc;
  159. }
  160. /**
  161. * Return reference of a packet location
  162. * @arg loc packet location object.
  163. */
  164. void rtnl_pktloc_put(struct rtnl_pktloc *loc)
  165. {
  166. if (!loc)
  167. return;
  168. loc->refcnt--;
  169. if (loc->refcnt <= 0)
  170. rtnl_pktloc_free(loc);
  171. }
  172. /**
  173. * Add a packet location to the hash table
  174. * @arg loc packet location object
  175. *
  176. * @return 0 on success or a negative error code.
  177. */
  178. int rtnl_pktloc_add(struct rtnl_pktloc *loc)
  179. {
  180. struct rtnl_pktloc *l;
  181. if (__pktloc_lookup(loc->name, &l) == 0) {
  182. rtnl_pktloc_put(l);
  183. return -NLE_EXIST;
  184. }
  185. NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u "
  186. "offset=%u mask=%#x shift=%u refnt=%u\n",
  187. loc->name, loc->align, loc->layer, loc->offset,
  188. loc->mask, loc->shift, loc->refcnt);
  189. nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
  190. return 0;
  191. }
  192. void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg)
  193. {
  194. struct rtnl_pktloc *loc;
  195. int i;
  196. /* ignore errors */
  197. read_pktlocs();
  198. for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
  199. nl_list_for_each_entry(loc, &pktloc_name_ht[i], list)
  200. cb(loc, arg);
  201. }
  202. static int __init pktloc_init(void)
  203. {
  204. int i;
  205. for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
  206. nl_init_list_head(&pktloc_name_ht[i]);
  207. return 0;
  208. }
  209. /** @} */