18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016 Citrix Systems Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 58c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 68c2ecf20Sopenharmony_ci * as published by the Free Softare Foundation; or, when distributed 78c2ecf20Sopenharmony_ci * separately from the Linux kernel or incorporated into other 88c2ecf20Sopenharmony_ci * software packages, subject to the following license: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 118c2ecf20Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 128c2ecf20Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 138c2ecf20Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 148c2ecf20Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 158c2ecf20Sopenharmony_ci * the following conditions: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 188c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 218c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 228c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 238c2ecf20Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 248c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 258c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 268c2ecf20Sopenharmony_ci * IN THE SOFTWARE. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define XEN_NETIF_DEFINE_TOEPLITZ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "common.h" 328c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 338c2ecf20Sopenharmony_ci#include <linux/rculist.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void xenvif_add_hash(struct xenvif *vif, const u8 *tag, 368c2ecf20Sopenharmony_ci unsigned int len, u32 val) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct xenvif_hash_cache_entry *new, *entry, *oldest; 398c2ecf20Sopenharmony_ci unsigned long flags; 408c2ecf20Sopenharmony_ci bool found; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci new = kmalloc(sizeof(*entry), GFP_ATOMIC); 438c2ecf20Sopenharmony_ci if (!new) 448c2ecf20Sopenharmony_ci return; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci memcpy(new->tag, tag, len); 478c2ecf20Sopenharmony_ci new->len = len; 488c2ecf20Sopenharmony_ci new->val = val; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci spin_lock_irqsave(&vif->hash.cache.lock, flags); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci found = false; 538c2ecf20Sopenharmony_ci oldest = NULL; 548c2ecf20Sopenharmony_ci list_for_each_entry_rcu(entry, &vif->hash.cache.list, link, 558c2ecf20Sopenharmony_ci lockdep_is_held(&vif->hash.cache.lock)) { 568c2ecf20Sopenharmony_ci /* Make sure we don't add duplicate entries */ 578c2ecf20Sopenharmony_ci if (entry->len == len && 588c2ecf20Sopenharmony_ci memcmp(entry->tag, tag, len) == 0) 598c2ecf20Sopenharmony_ci found = true; 608c2ecf20Sopenharmony_ci if (!oldest || entry->seq < oldest->seq) 618c2ecf20Sopenharmony_ci oldest = entry; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (!found) { 658c2ecf20Sopenharmony_ci new->seq = atomic_inc_return(&vif->hash.cache.seq); 668c2ecf20Sopenharmony_ci list_add_rcu(&new->link, &vif->hash.cache.list); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (++vif->hash.cache.count > xenvif_hash_cache_size) { 698c2ecf20Sopenharmony_ci list_del_rcu(&oldest->link); 708c2ecf20Sopenharmony_ci vif->hash.cache.count--; 718c2ecf20Sopenharmony_ci kfree_rcu(oldest, rcu); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vif->hash.cache.lock, flags); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (found) 788c2ecf20Sopenharmony_ci kfree(new); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic u32 xenvif_new_hash(struct xenvif *vif, const u8 *data, 828c2ecf20Sopenharmony_ci unsigned int len) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u32 val; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci val = xen_netif_toeplitz_hash(vif->hash.key, 878c2ecf20Sopenharmony_ci sizeof(vif->hash.key), 888c2ecf20Sopenharmony_ci data, len); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (xenvif_hash_cache_size != 0) 918c2ecf20Sopenharmony_ci xenvif_add_hash(vif, data, len, val); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return val; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void xenvif_flush_hash(struct xenvif *vif) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct xenvif_hash_cache_entry *entry; 998c2ecf20Sopenharmony_ci unsigned long flags; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (xenvif_hash_cache_size == 0) 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci spin_lock_irqsave(&vif->hash.cache.lock, flags); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci list_for_each_entry_rcu(entry, &vif->hash.cache.list, link, 1078c2ecf20Sopenharmony_ci lockdep_is_held(&vif->hash.cache.lock)) { 1088c2ecf20Sopenharmony_ci list_del_rcu(&entry->link); 1098c2ecf20Sopenharmony_ci vif->hash.cache.count--; 1108c2ecf20Sopenharmony_ci kfree_rcu(entry, rcu); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vif->hash.cache.lock, flags); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic u32 xenvif_find_hash(struct xenvif *vif, const u8 *data, 1178c2ecf20Sopenharmony_ci unsigned int len) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct xenvif_hash_cache_entry *entry; 1208c2ecf20Sopenharmony_ci u32 val; 1218c2ecf20Sopenharmony_ci bool found; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (len >= XEN_NETBK_HASH_TAG_SIZE) 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (xenvif_hash_cache_size == 0) 1278c2ecf20Sopenharmony_ci return xenvif_new_hash(vif, data, len); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci rcu_read_lock(); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci found = false; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci list_for_each_entry_rcu(entry, &vif->hash.cache.list, link) { 1348c2ecf20Sopenharmony_ci if (entry->len == len && 1358c2ecf20Sopenharmony_ci memcmp(entry->tag, data, len) == 0) { 1368c2ecf20Sopenharmony_ci val = entry->val; 1378c2ecf20Sopenharmony_ci entry->seq = atomic_inc_return(&vif->hash.cache.seq); 1388c2ecf20Sopenharmony_ci found = true; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci rcu_read_unlock(); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!found) 1468c2ecf20Sopenharmony_ci val = xenvif_new_hash(vif, data, len); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return val; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid xenvif_set_skb_hash(struct xenvif *vif, struct sk_buff *skb) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct flow_keys flow; 1548c2ecf20Sopenharmony_ci u32 hash = 0; 1558c2ecf20Sopenharmony_ci enum pkt_hash_types type = PKT_HASH_TYPE_NONE; 1568c2ecf20Sopenharmony_ci u32 flags = vif->hash.flags; 1578c2ecf20Sopenharmony_ci bool has_tcp_hdr; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Quick rejection test: If the network protocol doesn't 1608c2ecf20Sopenharmony_ci * correspond to any enabled hash type then there's no point 1618c2ecf20Sopenharmony_ci * in parsing the packet header. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci switch (skb->protocol) { 1648c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 1658c2ecf20Sopenharmony_ci if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP | 1668c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV4)) 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci goto done; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 1728c2ecf20Sopenharmony_ci if (flags & (XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP | 1738c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV6)) 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci goto done; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci default: 1798c2ecf20Sopenharmony_ci goto done; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci memset(&flow, 0, sizeof(flow)); 1838c2ecf20Sopenharmony_ci if (!skb_flow_dissect_flow_keys(skb, &flow, 0)) 1848c2ecf20Sopenharmony_ci goto done; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci has_tcp_hdr = (flow.basic.ip_proto == IPPROTO_TCP) && 1878c2ecf20Sopenharmony_ci !(flow.control.flags & FLOW_DIS_IS_FRAGMENT); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci switch (skb->protocol) { 1908c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 1918c2ecf20Sopenharmony_ci if (has_tcp_hdr && 1928c2ecf20Sopenharmony_ci (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)) { 1938c2ecf20Sopenharmony_ci u8 data[12]; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci memcpy(&data[0], &flow.addrs.v4addrs.src, 4); 1968c2ecf20Sopenharmony_ci memcpy(&data[4], &flow.addrs.v4addrs.dst, 4); 1978c2ecf20Sopenharmony_ci memcpy(&data[8], &flow.ports.src, 2); 1988c2ecf20Sopenharmony_ci memcpy(&data[10], &flow.ports.dst, 2); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci hash = xenvif_find_hash(vif, data, sizeof(data)); 2018c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L4; 2028c2ecf20Sopenharmony_ci } else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4) { 2038c2ecf20Sopenharmony_ci u8 data[8]; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci memcpy(&data[0], &flow.addrs.v4addrs.src, 4); 2068c2ecf20Sopenharmony_ci memcpy(&data[4], &flow.addrs.v4addrs.dst, 4); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci hash = xenvif_find_hash(vif, data, sizeof(data)); 2098c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L3; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 2158c2ecf20Sopenharmony_ci if (has_tcp_hdr && 2168c2ecf20Sopenharmony_ci (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)) { 2178c2ecf20Sopenharmony_ci u8 data[36]; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memcpy(&data[0], &flow.addrs.v6addrs.src, 16); 2208c2ecf20Sopenharmony_ci memcpy(&data[16], &flow.addrs.v6addrs.dst, 16); 2218c2ecf20Sopenharmony_ci memcpy(&data[32], &flow.ports.src, 2); 2228c2ecf20Sopenharmony_ci memcpy(&data[34], &flow.ports.dst, 2); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci hash = xenvif_find_hash(vif, data, sizeof(data)); 2258c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L4; 2268c2ecf20Sopenharmony_ci } else if (flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6) { 2278c2ecf20Sopenharmony_ci u8 data[32]; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci memcpy(&data[0], &flow.addrs.v6addrs.src, 16); 2308c2ecf20Sopenharmony_ci memcpy(&data[16], &flow.addrs.v6addrs.dst, 16); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci hash = xenvif_find_hash(vif, data, sizeof(data)); 2338c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L3; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cidone: 2408c2ecf20Sopenharmony_ci if (type == PKT_HASH_TYPE_NONE) 2418c2ecf20Sopenharmony_ci skb_clear_hash(skb); 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci __skb_set_sw_hash(skb, hash, type == PKT_HASH_TYPE_L4); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciu32 xenvif_set_hash_alg(struct xenvif *vif, u32 alg) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci switch (alg) { 2498c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE: 2508c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ: 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci default: 2548c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci vif->hash.alg = alg; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciu32 xenvif_get_hash_flags(struct xenvif *vif, u32 *flags) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) 2658c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci *flags = XEN_NETIF_CTRL_HASH_TYPE_IPV4 | 2688c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP | 2698c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV6 | 2708c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciu32 xenvif_set_hash_flags(struct xenvif *vif, u32 flags) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci if (flags & ~(XEN_NETIF_CTRL_HASH_TYPE_IPV4 | 2788c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP | 2798c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV6 | 2808c2ecf20Sopenharmony_ci XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)) 2818c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE) 2848c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci vif->hash.flags = flags; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciu32 xenvif_set_hash_key(struct xenvif *vif, u32 gref, u32 len) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci u8 *key = vif->hash.key; 2948c2ecf20Sopenharmony_ci struct gnttab_copy copy_op = { 2958c2ecf20Sopenharmony_ci .source.u.ref = gref, 2968c2ecf20Sopenharmony_ci .source.domid = vif->domid, 2978c2ecf20Sopenharmony_ci .dest.u.gmfn = virt_to_gfn(key), 2988c2ecf20Sopenharmony_ci .dest.domid = DOMID_SELF, 2998c2ecf20Sopenharmony_ci .dest.offset = xen_offset_in_page(key), 3008c2ecf20Sopenharmony_ci .len = len, 3018c2ecf20Sopenharmony_ci .flags = GNTCOPY_source_gref 3028c2ecf20Sopenharmony_ci }; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (len > XEN_NETBK_MAX_HASH_KEY_SIZE) 3058c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (copy_op.len != 0) { 3088c2ecf20Sopenharmony_ci gnttab_batch_copy(©_op, 1); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (copy_op.status != GNTST_okay) 3118c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* Clear any remaining key octets */ 3158c2ecf20Sopenharmony_ci if (len < XEN_NETBK_MAX_HASH_KEY_SIZE) 3168c2ecf20Sopenharmony_ci memset(key + len, 0, XEN_NETBK_MAX_HASH_KEY_SIZE - len); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci xenvif_flush_hash(vif); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciu32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci if (size > XEN_NETBK_MAX_HASH_MAPPING_SIZE) 3268c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci vif->hash.size = size; 3298c2ecf20Sopenharmony_ci memset(vif->hash.mapping[vif->hash.mapping_sel], 0, 3308c2ecf20Sopenharmony_ci sizeof(u32) * size); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ciu32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len, 3368c2ecf20Sopenharmony_ci u32 off) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci u32 *mapping = vif->hash.mapping[!vif->hash.mapping_sel]; 3398c2ecf20Sopenharmony_ci unsigned int nr = 1; 3408c2ecf20Sopenharmony_ci struct gnttab_copy copy_op[2] = {{ 3418c2ecf20Sopenharmony_ci .source.u.ref = gref, 3428c2ecf20Sopenharmony_ci .source.domid = vif->domid, 3438c2ecf20Sopenharmony_ci .dest.domid = DOMID_SELF, 3448c2ecf20Sopenharmony_ci .len = len * sizeof(*mapping), 3458c2ecf20Sopenharmony_ci .flags = GNTCOPY_source_gref 3468c2ecf20Sopenharmony_ci }}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if ((off + len < off) || (off + len > vif->hash.size) || 3498c2ecf20Sopenharmony_ci len > XEN_PAGE_SIZE / sizeof(*mapping)) 3508c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci copy_op[0].dest.u.gmfn = virt_to_gfn(mapping + off); 3538c2ecf20Sopenharmony_ci copy_op[0].dest.offset = xen_offset_in_page(mapping + off); 3548c2ecf20Sopenharmony_ci if (copy_op[0].dest.offset + copy_op[0].len > XEN_PAGE_SIZE) { 3558c2ecf20Sopenharmony_ci copy_op[1] = copy_op[0]; 3568c2ecf20Sopenharmony_ci copy_op[1].source.offset = XEN_PAGE_SIZE - copy_op[0].dest.offset; 3578c2ecf20Sopenharmony_ci copy_op[1].dest.u.gmfn = virt_to_gfn(mapping + off + len); 3588c2ecf20Sopenharmony_ci copy_op[1].dest.offset = 0; 3598c2ecf20Sopenharmony_ci copy_op[1].len = copy_op[0].len - copy_op[1].source.offset; 3608c2ecf20Sopenharmony_ci copy_op[0].len = copy_op[1].source.offset; 3618c2ecf20Sopenharmony_ci nr = 2; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci memcpy(mapping, vif->hash.mapping[vif->hash.mapping_sel], 3658c2ecf20Sopenharmony_ci vif->hash.size * sizeof(*mapping)); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (copy_op[0].len != 0) { 3688c2ecf20Sopenharmony_ci gnttab_batch_copy(copy_op, nr); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (copy_op[0].status != GNTST_okay || 3718c2ecf20Sopenharmony_ci copy_op[nr - 1].status != GNTST_okay) 3728c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci while (len-- != 0) 3768c2ecf20Sopenharmony_ci if (mapping[off++] >= vif->num_queues) 3778c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci vif->hash.mapping_sel = !vif->hash.mapping_sel; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return XEN_NETIF_CTRL_STATUS_SUCCESS; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 3858c2ecf20Sopenharmony_civoid xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci unsigned int i; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci switch (vif->hash.alg) { 3908c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ: 3918c2ecf20Sopenharmony_ci seq_puts(m, "Hash Algorithm: TOEPLITZ\n"); 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE: 3958c2ecf20Sopenharmony_ci seq_puts(m, "Hash Algorithm: NONE\n"); 3968c2ecf20Sopenharmony_ci fallthrough; 3978c2ecf20Sopenharmony_ci default: 3988c2ecf20Sopenharmony_ci return; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (vif->hash.flags) { 4028c2ecf20Sopenharmony_ci seq_puts(m, "\nHash Flags:\n"); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4) 4058c2ecf20Sopenharmony_ci seq_puts(m, "- IPv4\n"); 4068c2ecf20Sopenharmony_ci if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP) 4078c2ecf20Sopenharmony_ci seq_puts(m, "- IPv4 + TCP\n"); 4088c2ecf20Sopenharmony_ci if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6) 4098c2ecf20Sopenharmony_ci seq_puts(m, "- IPv6\n"); 4108c2ecf20Sopenharmony_ci if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP) 4118c2ecf20Sopenharmony_ci seq_puts(m, "- IPv6 + TCP\n"); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci seq_puts(m, "\nHash Key:\n"); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci for (i = 0; i < XEN_NETBK_MAX_HASH_KEY_SIZE; ) { 4178c2ecf20Sopenharmony_ci unsigned int j, n; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci n = 8; 4208c2ecf20Sopenharmony_ci if (i + n >= XEN_NETBK_MAX_HASH_KEY_SIZE) 4218c2ecf20Sopenharmony_ci n = XEN_NETBK_MAX_HASH_KEY_SIZE - i; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci seq_printf(m, "[%2u - %2u]: ", i, i + n - 1); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci for (j = 0; j < n; j++, i++) 4268c2ecf20Sopenharmony_ci seq_printf(m, "%02x ", vif->hash.key[i]); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci seq_puts(m, "\n"); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (vif->hash.size != 0) { 4328c2ecf20Sopenharmony_ci const u32 *mapping = vif->hash.mapping[vif->hash.mapping_sel]; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci seq_puts(m, "\nHash Mapping:\n"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci for (i = 0; i < vif->hash.size; ) { 4378c2ecf20Sopenharmony_ci unsigned int j, n; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci n = 8; 4408c2ecf20Sopenharmony_ci if (i + n >= vif->hash.size) 4418c2ecf20Sopenharmony_ci n = vif->hash.size - i; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci seq_printf(m, "[%4u - %4u]: ", i, i + n - 1); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci for (j = 0; j < n; j++, i++) 4468c2ecf20Sopenharmony_ci seq_printf(m, "%4u ", mapping[i]); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci seq_puts(m, "\n"); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_civoid xenvif_init_hash(struct xenvif *vif) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci if (xenvif_hash_cache_size == 0) 4578c2ecf20Sopenharmony_ci return; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci BUG_ON(vif->hash.cache.count); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci spin_lock_init(&vif->hash.cache.lock); 4628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vif->hash.cache.list); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_civoid xenvif_deinit_hash(struct xenvif *vif) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci xenvif_flush_hash(vif); 4688c2ecf20Sopenharmony_ci} 469