hash.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (c) 2016 Citrix Systems Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License version 2
  6. * as published by the Free Softare Foundation; or, when distributed
  7. * separately from the Linux kernel or incorporated into other
  8. * software packages, subject to the following license:
  9. *
  10. * Permission is hereby granted, free of charge, to any person obtaining a copy
  11. * of this source file (the "Software"), to deal in the Software without
  12. * restriction, including without limitation the rights to use, copy, modify,
  13. * merge, publish, distribute, sublicense, and/or sell copies of the Software,
  14. * and to permit persons to whom the Software is furnished to do so, subject to
  15. * the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be included in
  18. * all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  26. * IN THE SOFTWARE.
  27. */
  28. #define XEN_NETIF_DEFINE_TOEPLITZ
  29. #include "common.h"
  30. #include <linux/vmalloc.h>
  31. #include <linux/rculist.h>
  32. static void xenvif_del_hash(struct rcu_head *rcu)
  33. {
  34. struct xenvif_hash_cache_entry *entry;
  35. entry = container_of(rcu, struct xenvif_hash_cache_entry, rcu);
  36. kfree(entry);
  37. }
  38. static void xenvif_add_hash(struct xenvif *vif, const u8 *tag,
  39. unsigned int len, u32 val)
  40. {
  41. struct xenvif_hash_cache_entry *new, *entry, *oldest;
  42. unsigned long flags;
  43. bool found;
  44. new = kmalloc(sizeof(*entry), GFP_KERNEL);
  45. if (!new)
  46. return;
  47. memcpy(new->tag, tag, len);
  48. new->len = len;
  49. new->val = val;
  50. spin_lock_irqsave(&vif->hash.cache.lock, flags);
  51. found = false;
  52. oldest = NULL;
  53. list_for_each_entry_rcu(entry, &vif->hash.cache.list, link) {
  54. /* Make sure we don't add duplicate entries */
  55. if (entry->len == len &&
  56. memcmp(entry->tag, tag, len) == 0)
  57. found = true;
  58. if (!oldest || entry->seq < oldest->seq)
  59. oldest = entry;
  60. }
  61. if (!found) {
  62. new->seq = atomic_inc_return(&vif->hash.cache.seq);
  63. list_add_rcu(&new->link, &vif->hash.cache.list);
  64. if (++vif->hash.cache.count > xenvif_hash_cache_size) {
  65. list_del_rcu(&oldest->link);
  66. vif->hash.cache.count--;
  67. call_rcu(&oldest->rcu, xenvif_del_hash);
  68. }
  69. }
  70. spin_unlock_irqrestore(&vif->hash.cache.lock, flags);
  71. if (found)
  72. kfree(new);
  73. }
  74. static u32 xenvif_new_hash(struct xenvif *vif, const u8 *data,
  75. unsigned int len)
  76. {
  77. u32 val;
  78. val = xen_netif_toeplitz_hash(vif->hash.key,
  79. sizeof(vif->hash.key),
  80. data, len);
  81. if (xenvif_hash_cache_size != 0)
  82. xenvif_add_hash(vif, data, len, val);
  83. return val;
  84. }
  85. static void xenvif_flush_hash(struct xenvif *vif)
  86. {
  87. struct xenvif_hash_cache_entry *entry;
  88. unsigned long flags;
  89. if (xenvif_hash_cache_size == 0)
  90. return;
  91. spin_lock_irqsave(&vif->hash.cache.lock, flags);
  92. list_for_each_entry_rcu(entry, &vif->hash.cache.list, link) {
  93. list_del_rcu(&entry->link);
  94. vif->hash.cache.count--;
  95. call_rcu(&entry->rcu, xenvif_del_hash);
  96. }
  97. spin_unlock_irqrestore(&vif->hash.cache.lock, flags);
  98. }
  99. static u32 xenvif_find_hash(struct xenvif *vif, const u8 *data,
  100. unsigned int len)
  101. {
  102. struct xenvif_hash_cache_entry *entry;
  103. u32 val;
  104. bool found;
  105. if (len >= XEN_NETBK_HASH_TAG_SIZE)
  106. return 0;
  107. if (xenvif_hash_cache_size == 0)
  108. return xenvif_new_hash(vif, data, len);
  109. rcu_read_lock();
  110. found = false;
  111. list_for_each_entry_rcu(entry, &vif->hash.cache.list, link) {
  112. if (entry->len == len &&
  113. memcmp(entry->tag, data, len) == 0) {
  114. val = entry->val;
  115. entry->seq = atomic_inc_return(&vif->hash.cache.seq);
  116. found = true;
  117. break;
  118. }
  119. }
  120. rcu_read_unlock();
  121. if (!found)
  122. val = xenvif_new_hash(vif, data, len);
  123. return val;
  124. }
  125. void xenvif_set_skb_hash(struct xenvif *vif, struct sk_buff *skb)
  126. {
  127. struct flow_keys flow;
  128. u32 hash = 0;
  129. enum pkt_hash_types type = PKT_HASH_TYPE_NONE;
  130. u32 flags = vif->hash.flags;
  131. bool has_tcp_hdr;
  132. /* Quick rejection test: If the network protocol doesn't
  133. * correspond to any enabled hash type then there's no point
  134. * in parsing the packet header.
  135. */
  136. switch (skb->protocol) {
  137. case htons(ETH_P_IP):
  138. if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
  139. XEN_NETIF_CTRL_HASH_TYPE_IPV4))
  140. break;
  141. goto done;
  142. case htons(ETH_P_IPV6):
  143. if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP |
  144. XEN_NETIF_CTRL_HASH_TYPE_IPV6))
  145. break;
  146. goto done;
  147. default:
  148. goto done;
  149. }
  150. memset(&flow, 0, sizeof(flow));
  151. if (!skb_flow_dissect_flow_keys(skb, &flow, 0))
  152. goto done;
  153. has_tcp_hdr = (flow.basic.ip_proto == IPPROTO_TCP) &&
  154. !(flow.control.flags & FLOW_DIS_IS_FRAGMENT);
  155. switch (skb->protocol) {
  156. case htons(ETH_P_IP):
  157. if (has_tcp_hdr &&
  158. (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)) {
  159. u8 data[12];
  160. memcpy(&data[0], &flow.addrs.v4addrs.src, 4);
  161. memcpy(&data[4], &flow.addrs.v4addrs.dst, 4);
  162. memcpy(&data[8], &flow.ports.src, 2);
  163. memcpy(&data[10], &flow.ports.dst, 2);
  164. hash = xenvif_find_hash(vif, data, sizeof(data));
  165. type = PKT_HASH_TYPE_L4;
  166. } else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4) {
  167. u8 data[8];
  168. memcpy(&data[0], &flow.addrs.v4addrs.src, 4);
  169. memcpy(&data[4], &flow.addrs.v4addrs.dst, 4);
  170. hash = xenvif_find_hash(vif, data, sizeof(data));
  171. type = PKT_HASH_TYPE_L3;
  172. }
  173. break;
  174. case htons(ETH_P_IPV6):
  175. if (has_tcp_hdr &&
  176. (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)) {
  177. u8 data[36];
  178. memcpy(&data[0], &flow.addrs.v6addrs.src, 16);
  179. memcpy(&data[16], &flow.addrs.v6addrs.dst, 16);
  180. memcpy(&data[32], &flow.ports.src, 2);
  181. memcpy(&data[34], &flow.ports.dst, 2);
  182. hash = xenvif_find_hash(vif, data, sizeof(data));
  183. type = PKT_HASH_TYPE_L4;
  184. } else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6) {
  185. u8 data[32];
  186. memcpy(&data[0], &flow.addrs.v6addrs.src, 16);
  187. memcpy(&data[16], &flow.addrs.v6addrs.dst, 16);
  188. hash = xenvif_find_hash(vif, data, sizeof(data));
  189. type = PKT_HASH_TYPE_L3;
  190. }
  191. break;
  192. }
  193. done:
  194. if (type == PKT_HASH_TYPE_NONE)
  195. skb_clear_hash(skb);
  196. else
  197. __skb_set_sw_hash(skb, hash, type == PKT_HASH_TYPE_L4);
  198. }
  199. u32 xenvif_set_hash_alg(struct xenvif *vif, u32 alg)
  200. {
  201. switch (alg) {
  202. case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE:
  203. case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ:
  204. break;
  205. default:
  206. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  207. }
  208. vif->hash.alg = alg;
  209. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  210. }
  211. u32 xenvif_get_hash_flags(struct xenvif *vif, u32 *flags)
  212. {
  213. if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
  214. return XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED;
  215. *flags = XEN_NETIF_CTRL_HASH_TYPE_IPV4 |
  216. XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
  217. XEN_NETIF_CTRL_HASH_TYPE_IPV6 |
  218. XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP;
  219. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  220. }
  221. u32 xenvif_set_hash_flags(struct xenvif *vif, u32 flags)
  222. {
  223. if (flags & ~(XEN_NETIF_CTRL_HASH_TYPE_IPV4 |
  224. XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP |
  225. XEN_NETIF_CTRL_HASH_TYPE_IPV6 |
  226. XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP))
  227. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  228. if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
  229. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  230. vif->hash.flags = flags;
  231. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  232. }
  233. u32 xenvif_set_hash_key(struct xenvif *vif, u32 gref, u32 len)
  234. {
  235. u8 *key = vif->hash.key;
  236. struct gnttab_copy copy_op = {
  237. .source.u.ref = gref,
  238. .source.domid = vif->domid,
  239. .dest.u.gmfn = virt_to_gfn(key),
  240. .dest.domid = DOMID_SELF,
  241. .dest.offset = xen_offset_in_page(key),
  242. .len = len,
  243. .flags = GNTCOPY_source_gref
  244. };
  245. if (len > XEN_NETBK_MAX_HASH_KEY_SIZE)
  246. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  247. if (copy_op.len != 0) {
  248. gnttab_batch_copy(&copy_op, 1);
  249. if (copy_op.status != GNTST_okay)
  250. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  251. }
  252. /* Clear any remaining key octets */
  253. if (len < XEN_NETBK_MAX_HASH_KEY_SIZE)
  254. memset(key + len, 0, XEN_NETBK_MAX_HASH_KEY_SIZE - len);
  255. xenvif_flush_hash(vif);
  256. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  257. }
  258. u32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size)
  259. {
  260. if (size > XEN_NETBK_MAX_HASH_MAPPING_SIZE)
  261. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  262. vif->hash.size = size;
  263. memset(vif->hash.mapping, 0, sizeof(u32) * size);
  264. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  265. }
  266. u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
  267. u32 off)
  268. {
  269. u32 *mapping = &vif->hash.mapping[off];
  270. struct gnttab_copy copy_op = {
  271. .source.u.ref = gref,
  272. .source.domid = vif->domid,
  273. .dest.u.gmfn = virt_to_gfn(mapping),
  274. .dest.domid = DOMID_SELF,
  275. .dest.offset = xen_offset_in_page(mapping),
  276. .len = len * sizeof(u32),
  277. .flags = GNTCOPY_source_gref
  278. };
  279. if ((off + len > vif->hash.size) || copy_op.len > XEN_PAGE_SIZE)
  280. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  281. while (len-- != 0)
  282. if (mapping[off++] >= vif->num_queues)
  283. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  284. if (copy_op.len != 0) {
  285. gnttab_batch_copy(&copy_op, 1);
  286. if (copy_op.status != GNTST_okay)
  287. return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
  288. }
  289. return XEN_NETIF_CTRL_STATUS_SUCCESS;
  290. }
  291. void xenvif_init_hash(struct xenvif *vif)
  292. {
  293. if (xenvif_hash_cache_size == 0)
  294. return;
  295. spin_lock_init(&vif->hash.cache.lock);
  296. INIT_LIST_HEAD(&vif->hash.cache.list);
  297. }
  298. void xenvif_deinit_hash(struct xenvif *vif)
  299. {
  300. xenvif_flush_hash(vif);
  301. }