18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2014 Nicira, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "flow.h" 78c2ecf20Sopenharmony_ci#include "datapath.h" 88c2ecf20Sopenharmony_ci#include "flow_netlink.h" 98c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 108c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 128c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 138c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 148c2ecf20Sopenharmony_ci#include <net/llc_pdu.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/jhash.h> 178c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 188c2ecf20Sopenharmony_ci#include <linux/llc.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/in.h> 218c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 228c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 238c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 248c2ecf20Sopenharmony_ci#include <linux/ip.h> 258c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 268c2ecf20Sopenharmony_ci#include <linux/sctp.h> 278c2ecf20Sopenharmony_ci#include <linux/tcp.h> 288c2ecf20Sopenharmony_ci#include <linux/udp.h> 298c2ecf20Sopenharmony_ci#include <linux/icmp.h> 308c2ecf20Sopenharmony_ci#include <linux/icmpv6.h> 318c2ecf20Sopenharmony_ci#include <linux/rculist.h> 328c2ecf20Sopenharmony_ci#include <linux/sort.h> 338c2ecf20Sopenharmony_ci#include <net/ip.h> 348c2ecf20Sopenharmony_ci#include <net/ipv6.h> 358c2ecf20Sopenharmony_ci#include <net/ndisc.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define TBL_MIN_BUCKETS 1024 388c2ecf20Sopenharmony_ci#define MASK_ARRAY_SIZE_MIN 16 398c2ecf20Sopenharmony_ci#define REHASH_INTERVAL (10 * 60 * HZ) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define MC_DEFAULT_HASH_ENTRIES 256 428c2ecf20Sopenharmony_ci#define MC_HASH_SHIFT 8 438c2ecf20Sopenharmony_ci#define MC_HASH_SEGS ((sizeof(uint32_t) * 8) / MC_HASH_SHIFT) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct kmem_cache *flow_cache; 468c2ecf20Sopenharmony_cistruct kmem_cache *flow_stats_cache __read_mostly; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic u16 range_n_bytes(const struct sw_flow_key_range *range) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return range->end - range->start; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_civoid ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, 548c2ecf20Sopenharmony_ci bool full, const struct sw_flow_mask *mask) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int start = full ? 0 : mask->range.start; 578c2ecf20Sopenharmony_ci int len = full ? sizeof *dst : range_n_bytes(&mask->range); 588c2ecf20Sopenharmony_ci const long *m = (const long *)((const u8 *)&mask->key + start); 598c2ecf20Sopenharmony_ci const long *s = (const long *)((const u8 *)src + start); 608c2ecf20Sopenharmony_ci long *d = (long *)((u8 *)dst + start); 618c2ecf20Sopenharmony_ci int i; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* If 'full' is true then all of 'dst' is fully initialized. Otherwise, 648c2ecf20Sopenharmony_ci * if 'full' is false the memory outside of the 'mask->range' is left 658c2ecf20Sopenharmony_ci * uninitialized. This can be used as an optimization when further 668c2ecf20Sopenharmony_ci * operations on 'dst' only use contents within 'mask->range'. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci for (i = 0; i < len; i += sizeof(long)) 698c2ecf20Sopenharmony_ci *d++ = *s++ & *m++; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_alloc(void) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct sw_flow *flow; 758c2ecf20Sopenharmony_ci struct sw_flow_stats *stats; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci flow = kmem_cache_zalloc(flow_cache, GFP_KERNEL); 788c2ecf20Sopenharmony_ci if (!flow) 798c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci flow->stats_last_writer = -1; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Initialize the default stat node. */ 848c2ecf20Sopenharmony_ci stats = kmem_cache_alloc_node(flow_stats_cache, 858c2ecf20Sopenharmony_ci GFP_KERNEL | __GFP_ZERO, 868c2ecf20Sopenharmony_ci node_online(0) ? 0 : NUMA_NO_NODE); 878c2ecf20Sopenharmony_ci if (!stats) 888c2ecf20Sopenharmony_ci goto err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci spin_lock_init(&stats->lock); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci RCU_INIT_POINTER(flow->stats[0], stats); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci cpumask_set_cpu(0, &flow->cpu_used_mask); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return flow; 978c2ecf20Sopenharmony_cierr: 988c2ecf20Sopenharmony_ci kmem_cache_free(flow_cache, flow); 998c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciint ovs_flow_tbl_count(const struct flow_table *table) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return table->count; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void flow_free(struct sw_flow *flow) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int cpu; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (ovs_identifier_is_key(&flow->id)) 1128c2ecf20Sopenharmony_ci kfree(flow->id.unmasked_key); 1138c2ecf20Sopenharmony_ci if (flow->sf_acts) 1148c2ecf20Sopenharmony_ci ovs_nla_free_flow_actions((struct sw_flow_actions __force *) 1158c2ecf20Sopenharmony_ci flow->sf_acts); 1168c2ecf20Sopenharmony_ci /* We open code this to make sure cpu 0 is always considered */ 1178c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr_cpu_ids; 1188c2ecf20Sopenharmony_ci cpu = cpumask_next(cpu, &flow->cpu_used_mask)) { 1198c2ecf20Sopenharmony_ci if (flow->stats[cpu]) 1208c2ecf20Sopenharmony_ci kmem_cache_free(flow_stats_cache, 1218c2ecf20Sopenharmony_ci (struct sw_flow_stats __force *)flow->stats[cpu]); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci kmem_cache_free(flow_cache, flow); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void rcu_free_flow_callback(struct rcu_head *rcu) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci flow_free(flow); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_civoid ovs_flow_free(struct sw_flow *flow, bool deferred) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci if (!flow) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (deferred) 1408c2ecf20Sopenharmony_ci call_rcu(&flow->rcu, rcu_free_flow_callback); 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci flow_free(flow); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void __table_instance_destroy(struct table_instance *ti) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci kvfree(ti->buckets); 1488c2ecf20Sopenharmony_ci kfree(ti); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic struct table_instance *table_instance_alloc(int new_size) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct table_instance *ti = kmalloc(sizeof(*ti), GFP_KERNEL); 1548c2ecf20Sopenharmony_ci int i; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!ti) 1578c2ecf20Sopenharmony_ci return NULL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ti->buckets = kvmalloc_array(new_size, sizeof(struct hlist_head), 1608c2ecf20Sopenharmony_ci GFP_KERNEL); 1618c2ecf20Sopenharmony_ci if (!ti->buckets) { 1628c2ecf20Sopenharmony_ci kfree(ti); 1638c2ecf20Sopenharmony_ci return NULL; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci for (i = 0; i < new_size; i++) 1678c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&ti->buckets[i]); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ti->n_buckets = new_size; 1708c2ecf20Sopenharmony_ci ti->node_ver = 0; 1718c2ecf20Sopenharmony_ci get_random_bytes(&ti->hash_seed, sizeof(u32)); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return ti; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void __mask_array_destroy(struct mask_array *ma) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci free_percpu(ma->masks_usage_stats); 1798c2ecf20Sopenharmony_ci kfree(ma); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic void mask_array_rcu_cb(struct rcu_head *rcu) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct mask_array *ma = container_of(rcu, struct mask_array, rcu); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci __mask_array_destroy(ma); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void tbl_mask_array_reset_counters(struct mask_array *ma) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int i, cpu; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* As the per CPU counters are not atomic we can not go ahead and 1948c2ecf20Sopenharmony_ci * reset them from another CPU. To be able to still have an approximate 1958c2ecf20Sopenharmony_ci * zero based counter we store the value at reset, and subtract it 1968c2ecf20Sopenharmony_ci * later when processing. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci for (i = 0; i < ma->max; i++) { 1998c2ecf20Sopenharmony_ci ma->masks_usage_zero_cntr[i] = 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 2028c2ecf20Sopenharmony_ci struct mask_array_stats *stats; 2038c2ecf20Sopenharmony_ci unsigned int start; 2048c2ecf20Sopenharmony_ci u64 counter; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci stats = per_cpu_ptr(ma->masks_usage_stats, cpu); 2078c2ecf20Sopenharmony_ci do { 2088c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&stats->syncp); 2098c2ecf20Sopenharmony_ci counter = stats->usage_cntrs[i]; 2108c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ma->masks_usage_zero_cntr[i] += counter; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic struct mask_array *tbl_mask_array_alloc(int size) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct mask_array *new; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci size = max(MASK_ARRAY_SIZE_MIN, size); 2228c2ecf20Sopenharmony_ci new = kzalloc(sizeof(struct mask_array) + 2238c2ecf20Sopenharmony_ci sizeof(struct sw_flow_mask *) * size + 2248c2ecf20Sopenharmony_ci sizeof(u64) * size, GFP_KERNEL); 2258c2ecf20Sopenharmony_ci if (!new) 2268c2ecf20Sopenharmony_ci return NULL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci new->masks_usage_zero_cntr = (u64 *)((u8 *)new + 2298c2ecf20Sopenharmony_ci sizeof(struct mask_array) + 2308c2ecf20Sopenharmony_ci sizeof(struct sw_flow_mask *) * 2318c2ecf20Sopenharmony_ci size); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci new->masks_usage_stats = __alloc_percpu(sizeof(struct mask_array_stats) + 2348c2ecf20Sopenharmony_ci sizeof(u64) * size, 2358c2ecf20Sopenharmony_ci __alignof__(u64)); 2368c2ecf20Sopenharmony_ci if (!new->masks_usage_stats) { 2378c2ecf20Sopenharmony_ci kfree(new); 2388c2ecf20Sopenharmony_ci return NULL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci new->count = 0; 2428c2ecf20Sopenharmony_ci new->max = size; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return new; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int tbl_mask_array_realloc(struct flow_table *tbl, int size) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct mask_array *old; 2508c2ecf20Sopenharmony_ci struct mask_array *new; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci new = tbl_mask_array_alloc(size); 2538c2ecf20Sopenharmony_ci if (!new) 2548c2ecf20Sopenharmony_ci return -ENOMEM; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci old = ovsl_dereference(tbl->mask_array); 2578c2ecf20Sopenharmony_ci if (old) { 2588c2ecf20Sopenharmony_ci int i; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci for (i = 0; i < old->max; i++) { 2618c2ecf20Sopenharmony_ci if (ovsl_dereference(old->masks[i])) 2628c2ecf20Sopenharmony_ci new->masks[new->count++] = old->masks[i]; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci call_rcu(&old->rcu, mask_array_rcu_cb); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci rcu_assign_pointer(tbl->mask_array, new); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int tbl_mask_array_add_mask(struct flow_table *tbl, 2738c2ecf20Sopenharmony_ci struct sw_flow_mask *new) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct mask_array *ma = ovsl_dereference(tbl->mask_array); 2768c2ecf20Sopenharmony_ci int err, ma_count = READ_ONCE(ma->count); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (ma_count >= ma->max) { 2798c2ecf20Sopenharmony_ci err = tbl_mask_array_realloc(tbl, ma->max + 2808c2ecf20Sopenharmony_ci MASK_ARRAY_SIZE_MIN); 2818c2ecf20Sopenharmony_ci if (err) 2828c2ecf20Sopenharmony_ci return err; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ma = ovsl_dereference(tbl->mask_array); 2858c2ecf20Sopenharmony_ci } else { 2868c2ecf20Sopenharmony_ci /* On every add or delete we need to reset the counters so 2878c2ecf20Sopenharmony_ci * every new mask gets a fair chance of being prioritized. 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci tbl_mask_array_reset_counters(ma); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci BUG_ON(ovsl_dereference(ma->masks[ma_count])); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci rcu_assign_pointer(ma->masks[ma_count], new); 2958c2ecf20Sopenharmony_ci WRITE_ONCE(ma->count, ma_count + 1); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void tbl_mask_array_del_mask(struct flow_table *tbl, 3018c2ecf20Sopenharmony_ci struct sw_flow_mask *mask) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct mask_array *ma = ovsl_dereference(tbl->mask_array); 3048c2ecf20Sopenharmony_ci int i, ma_count = READ_ONCE(ma->count); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Remove the deleted mask pointers from the array */ 3078c2ecf20Sopenharmony_ci for (i = 0; i < ma_count; i++) { 3088c2ecf20Sopenharmony_ci if (mask == ovsl_dereference(ma->masks[i])) 3098c2ecf20Sopenharmony_ci goto found; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci BUG(); 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cifound: 3168c2ecf20Sopenharmony_ci WRITE_ONCE(ma->count, ma_count - 1); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci rcu_assign_pointer(ma->masks[i], ma->masks[ma_count - 1]); 3198c2ecf20Sopenharmony_ci RCU_INIT_POINTER(ma->masks[ma_count - 1], NULL); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci kfree_rcu(mask, rcu); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Shrink the mask array if necessary. */ 3248c2ecf20Sopenharmony_ci if (ma->max >= (MASK_ARRAY_SIZE_MIN * 2) && 3258c2ecf20Sopenharmony_ci ma_count <= (ma->max / 3)) 3268c2ecf20Sopenharmony_ci tbl_mask_array_realloc(tbl, ma->max / 2); 3278c2ecf20Sopenharmony_ci else 3288c2ecf20Sopenharmony_ci tbl_mask_array_reset_counters(ma); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* Remove 'mask' from the mask list, if it is not needed any more. */ 3338c2ecf20Sopenharmony_cistatic void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci if (mask) { 3368c2ecf20Sopenharmony_ci /* ovs-lock is required to protect mask-refcount and 3378c2ecf20Sopenharmony_ci * mask list. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_ci ASSERT_OVSL(); 3408c2ecf20Sopenharmony_ci BUG_ON(!mask->ref_count); 3418c2ecf20Sopenharmony_ci mask->ref_count--; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!mask->ref_count) 3448c2ecf20Sopenharmony_ci tbl_mask_array_del_mask(tbl, mask); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void __mask_cache_destroy(struct mask_cache *mc) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci free_percpu(mc->mask_cache); 3518c2ecf20Sopenharmony_ci kfree(mc); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void mask_cache_rcu_cb(struct rcu_head *rcu) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct mask_cache *mc = container_of(rcu, struct mask_cache, rcu); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci __mask_cache_destroy(mc); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic struct mask_cache *tbl_mask_cache_alloc(u32 size) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct mask_cache_entry __percpu *cache = NULL; 3648c2ecf20Sopenharmony_ci struct mask_cache *new; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Only allow size to be 0, or a power of 2, and does not exceed 3678c2ecf20Sopenharmony_ci * percpu allocation size. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if ((!is_power_of_2(size) && size != 0) || 3708c2ecf20Sopenharmony_ci (size * sizeof(struct mask_cache_entry)) > PCPU_MIN_UNIT_SIZE) 3718c2ecf20Sopenharmony_ci return NULL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci new = kzalloc(sizeof(*new), GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!new) 3758c2ecf20Sopenharmony_ci return NULL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci new->cache_size = size; 3788c2ecf20Sopenharmony_ci if (new->cache_size > 0) { 3798c2ecf20Sopenharmony_ci cache = __alloc_percpu(array_size(sizeof(struct mask_cache_entry), 3808c2ecf20Sopenharmony_ci new->cache_size), 3818c2ecf20Sopenharmony_ci __alignof__(struct mask_cache_entry)); 3828c2ecf20Sopenharmony_ci if (!cache) { 3838c2ecf20Sopenharmony_ci kfree(new); 3848c2ecf20Sopenharmony_ci return NULL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci new->mask_cache = cache; 3898c2ecf20Sopenharmony_ci return new; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ciint ovs_flow_tbl_masks_cache_resize(struct flow_table *table, u32 size) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct mask_cache *mc = rcu_dereference_ovsl(table->mask_cache); 3948c2ecf20Sopenharmony_ci struct mask_cache *new; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (size == mc->cache_size) 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if ((!is_power_of_2(size) && size != 0) || 4008c2ecf20Sopenharmony_ci (size * sizeof(struct mask_cache_entry)) > PCPU_MIN_UNIT_SIZE) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci new = tbl_mask_cache_alloc(size); 4048c2ecf20Sopenharmony_ci if (!new) 4058c2ecf20Sopenharmony_ci return -ENOMEM; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci rcu_assign_pointer(table->mask_cache, new); 4088c2ecf20Sopenharmony_ci call_rcu(&mc->rcu, mask_cache_rcu_cb); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciint ovs_flow_tbl_init(struct flow_table *table) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct table_instance *ti, *ufid_ti; 4168c2ecf20Sopenharmony_ci struct mask_cache *mc; 4178c2ecf20Sopenharmony_ci struct mask_array *ma; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci mc = tbl_mask_cache_alloc(MC_DEFAULT_HASH_ENTRIES); 4208c2ecf20Sopenharmony_ci if (!mc) 4218c2ecf20Sopenharmony_ci return -ENOMEM; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ma = tbl_mask_array_alloc(MASK_ARRAY_SIZE_MIN); 4248c2ecf20Sopenharmony_ci if (!ma) 4258c2ecf20Sopenharmony_ci goto free_mask_cache; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ti = table_instance_alloc(TBL_MIN_BUCKETS); 4288c2ecf20Sopenharmony_ci if (!ti) 4298c2ecf20Sopenharmony_ci goto free_mask_array; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS); 4328c2ecf20Sopenharmony_ci if (!ufid_ti) 4338c2ecf20Sopenharmony_ci goto free_ti; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci rcu_assign_pointer(table->ti, ti); 4368c2ecf20Sopenharmony_ci rcu_assign_pointer(table->ufid_ti, ufid_ti); 4378c2ecf20Sopenharmony_ci rcu_assign_pointer(table->mask_array, ma); 4388c2ecf20Sopenharmony_ci rcu_assign_pointer(table->mask_cache, mc); 4398c2ecf20Sopenharmony_ci table->last_rehash = jiffies; 4408c2ecf20Sopenharmony_ci table->count = 0; 4418c2ecf20Sopenharmony_ci table->ufid_count = 0; 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cifree_ti: 4458c2ecf20Sopenharmony_ci __table_instance_destroy(ti); 4468c2ecf20Sopenharmony_cifree_mask_array: 4478c2ecf20Sopenharmony_ci __mask_array_destroy(ma); 4488c2ecf20Sopenharmony_cifree_mask_cache: 4498c2ecf20Sopenharmony_ci __mask_cache_destroy(mc); 4508c2ecf20Sopenharmony_ci return -ENOMEM; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct table_instance *ti; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci ti = container_of(rcu, struct table_instance, rcu); 4588c2ecf20Sopenharmony_ci __table_instance_destroy(ti); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic void table_instance_flow_free(struct flow_table *table, 4628c2ecf20Sopenharmony_ci struct table_instance *ti, 4638c2ecf20Sopenharmony_ci struct table_instance *ufid_ti, 4648c2ecf20Sopenharmony_ci struct sw_flow *flow) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci hlist_del_rcu(&flow->flow_table.node[ti->node_ver]); 4678c2ecf20Sopenharmony_ci table->count--; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (ovs_identifier_is_ufid(&flow->id)) { 4708c2ecf20Sopenharmony_ci hlist_del_rcu(&flow->ufid_table.node[ufid_ti->node_ver]); 4718c2ecf20Sopenharmony_ci table->ufid_count--; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci flow_mask_remove(table, flow->mask); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 4788c2ecf20Sopenharmony_civoid table_instance_flow_flush(struct flow_table *table, 4798c2ecf20Sopenharmony_ci struct table_instance *ti, 4808c2ecf20Sopenharmony_ci struct table_instance *ufid_ti) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci int i; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci for (i = 0; i < ti->n_buckets; i++) { 4858c2ecf20Sopenharmony_ci struct hlist_head *head = &ti->buckets[i]; 4868c2ecf20Sopenharmony_ci struct hlist_node *n; 4878c2ecf20Sopenharmony_ci struct sw_flow *flow; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(flow, n, head, 4908c2ecf20Sopenharmony_ci flow_table.node[ti->node_ver]) { 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci table_instance_flow_free(table, ti, ufid_ti, 4938c2ecf20Sopenharmony_ci flow); 4948c2ecf20Sopenharmony_ci ovs_flow_free(flow, true); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (WARN_ON(table->count != 0 || 4998c2ecf20Sopenharmony_ci table->ufid_count != 0)) { 5008c2ecf20Sopenharmony_ci table->count = 0; 5018c2ecf20Sopenharmony_ci table->ufid_count = 0; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic void table_instance_destroy(struct table_instance *ti, 5068c2ecf20Sopenharmony_ci struct table_instance *ufid_ti) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb); 5098c2ecf20Sopenharmony_ci call_rcu(&ufid_ti->rcu, flow_tbl_destroy_rcu_cb); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* No need for locking this function is called from RCU callback or 5138c2ecf20Sopenharmony_ci * error path. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_civoid ovs_flow_tbl_destroy(struct flow_table *table) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct table_instance *ti = rcu_dereference_raw(table->ti); 5188c2ecf20Sopenharmony_ci struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti); 5198c2ecf20Sopenharmony_ci struct mask_cache *mc = rcu_dereference_raw(table->mask_cache); 5208c2ecf20Sopenharmony_ci struct mask_array *ma = rcu_dereference_raw(table->mask_array); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci call_rcu(&mc->rcu, mask_cache_rcu_cb); 5238c2ecf20Sopenharmony_ci call_rcu(&ma->rcu, mask_array_rcu_cb); 5248c2ecf20Sopenharmony_ci table_instance_destroy(ti, ufid_ti); 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, 5288c2ecf20Sopenharmony_ci u32 *bucket, u32 *last) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct sw_flow *flow; 5318c2ecf20Sopenharmony_ci struct hlist_head *head; 5328c2ecf20Sopenharmony_ci int ver; 5338c2ecf20Sopenharmony_ci int i; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ver = ti->node_ver; 5368c2ecf20Sopenharmony_ci while (*bucket < ti->n_buckets) { 5378c2ecf20Sopenharmony_ci i = 0; 5388c2ecf20Sopenharmony_ci head = &ti->buckets[*bucket]; 5398c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(flow, head, flow_table.node[ver]) { 5408c2ecf20Sopenharmony_ci if (i < *last) { 5418c2ecf20Sopenharmony_ci i++; 5428c2ecf20Sopenharmony_ci continue; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci *last = i + 1; 5458c2ecf20Sopenharmony_ci return flow; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci (*bucket)++; 5488c2ecf20Sopenharmony_ci *last = 0; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return NULL; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic struct hlist_head *find_bucket(struct table_instance *ti, u32 hash) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci hash = jhash_1word(hash, ti->hash_seed); 5578c2ecf20Sopenharmony_ci return &ti->buckets[hash & (ti->n_buckets - 1)]; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void table_instance_insert(struct table_instance *ti, 5618c2ecf20Sopenharmony_ci struct sw_flow *flow) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct hlist_head *head; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci head = find_bucket(ti, flow->flow_table.hash); 5668c2ecf20Sopenharmony_ci hlist_add_head_rcu(&flow->flow_table.node[ti->node_ver], head); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic void ufid_table_instance_insert(struct table_instance *ti, 5708c2ecf20Sopenharmony_ci struct sw_flow *flow) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct hlist_head *head; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci head = find_bucket(ti, flow->ufid_table.hash); 5758c2ecf20Sopenharmony_ci hlist_add_head_rcu(&flow->ufid_table.node[ti->node_ver], head); 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic void flow_table_copy_flows(struct table_instance *old, 5798c2ecf20Sopenharmony_ci struct table_instance *new, bool ufid) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci int old_ver; 5828c2ecf20Sopenharmony_ci int i; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci old_ver = old->node_ver; 5858c2ecf20Sopenharmony_ci new->node_ver = !old_ver; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Insert in new table. */ 5888c2ecf20Sopenharmony_ci for (i = 0; i < old->n_buckets; i++) { 5898c2ecf20Sopenharmony_ci struct sw_flow *flow; 5908c2ecf20Sopenharmony_ci struct hlist_head *head = &old->buckets[i]; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (ufid) 5938c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(flow, head, 5948c2ecf20Sopenharmony_ci ufid_table.node[old_ver], 5958c2ecf20Sopenharmony_ci lockdep_ovsl_is_held()) 5968c2ecf20Sopenharmony_ci ufid_table_instance_insert(new, flow); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(flow, head, 5998c2ecf20Sopenharmony_ci flow_table.node[old_ver], 6008c2ecf20Sopenharmony_ci lockdep_ovsl_is_held()) 6018c2ecf20Sopenharmony_ci table_instance_insert(new, flow); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic struct table_instance *table_instance_rehash(struct table_instance *ti, 6068c2ecf20Sopenharmony_ci int n_buckets, bool ufid) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct table_instance *new_ti; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci new_ti = table_instance_alloc(n_buckets); 6118c2ecf20Sopenharmony_ci if (!new_ti) 6128c2ecf20Sopenharmony_ci return NULL; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci flow_table_copy_flows(ti, new_ti, ufid); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return new_ti; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ciint ovs_flow_tbl_flush(struct flow_table *flow_table) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct table_instance *old_ti, *new_ti; 6228c2ecf20Sopenharmony_ci struct table_instance *old_ufid_ti, *new_ufid_ti; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci new_ti = table_instance_alloc(TBL_MIN_BUCKETS); 6258c2ecf20Sopenharmony_ci if (!new_ti) 6268c2ecf20Sopenharmony_ci return -ENOMEM; 6278c2ecf20Sopenharmony_ci new_ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS); 6288c2ecf20Sopenharmony_ci if (!new_ufid_ti) 6298c2ecf20Sopenharmony_ci goto err_free_ti; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci old_ti = ovsl_dereference(flow_table->ti); 6328c2ecf20Sopenharmony_ci old_ufid_ti = ovsl_dereference(flow_table->ufid_ti); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci rcu_assign_pointer(flow_table->ti, new_ti); 6358c2ecf20Sopenharmony_ci rcu_assign_pointer(flow_table->ufid_ti, new_ufid_ti); 6368c2ecf20Sopenharmony_ci flow_table->last_rehash = jiffies; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci table_instance_flow_flush(flow_table, old_ti, old_ufid_ti); 6398c2ecf20Sopenharmony_ci table_instance_destroy(old_ti, old_ufid_ti); 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cierr_free_ti: 6438c2ecf20Sopenharmony_ci __table_instance_destroy(new_ti); 6448c2ecf20Sopenharmony_ci return -ENOMEM; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic u32 flow_hash(const struct sw_flow_key *key, 6488c2ecf20Sopenharmony_ci const struct sw_flow_key_range *range) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci const u32 *hash_key = (const u32 *)((const u8 *)key + range->start); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Make sure number of hash bytes are multiple of u32. */ 6538c2ecf20Sopenharmony_ci int hash_u32s = range_n_bytes(range) >> 2; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return jhash2(hash_key, hash_u32s, 0); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int flow_key_start(const struct sw_flow_key *key) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci if (key->tun_proto) 6618c2ecf20Sopenharmony_ci return 0; 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci return rounddown(offsetof(struct sw_flow_key, phy), 6648c2ecf20Sopenharmony_ci sizeof(long)); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic bool cmp_key(const struct sw_flow_key *key1, 6688c2ecf20Sopenharmony_ci const struct sw_flow_key *key2, 6698c2ecf20Sopenharmony_ci int key_start, int key_end) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci const long *cp1 = (const long *)((const u8 *)key1 + key_start); 6728c2ecf20Sopenharmony_ci const long *cp2 = (const long *)((const u8 *)key2 + key_start); 6738c2ecf20Sopenharmony_ci long diffs = 0; 6748c2ecf20Sopenharmony_ci int i; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci for (i = key_start; i < key_end; i += sizeof(long)) 6778c2ecf20Sopenharmony_ci diffs |= *cp1++ ^ *cp2++; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return diffs == 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic bool flow_cmp_masked_key(const struct sw_flow *flow, 6838c2ecf20Sopenharmony_ci const struct sw_flow_key *key, 6848c2ecf20Sopenharmony_ci const struct sw_flow_key_range *range) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci return cmp_key(&flow->key, key, range->start, range->end); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, 6908c2ecf20Sopenharmony_ci const struct sw_flow_match *match) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct sw_flow_key *key = match->key; 6938c2ecf20Sopenharmony_ci int key_start = flow_key_start(key); 6948c2ecf20Sopenharmony_ci int key_end = match->range.end; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci BUG_ON(ovs_identifier_is_ufid(&flow->id)); 6978c2ecf20Sopenharmony_ci return cmp_key(flow->id.unmasked_key, key, key_start, key_end); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic struct sw_flow *masked_flow_lookup(struct table_instance *ti, 7018c2ecf20Sopenharmony_ci const struct sw_flow_key *unmasked, 7028c2ecf20Sopenharmony_ci const struct sw_flow_mask *mask, 7038c2ecf20Sopenharmony_ci u32 *n_mask_hit) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct sw_flow *flow; 7068c2ecf20Sopenharmony_ci struct hlist_head *head; 7078c2ecf20Sopenharmony_ci u32 hash; 7088c2ecf20Sopenharmony_ci struct sw_flow_key masked_key; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci ovs_flow_mask_key(&masked_key, unmasked, false, mask); 7118c2ecf20Sopenharmony_ci hash = flow_hash(&masked_key, &mask->range); 7128c2ecf20Sopenharmony_ci head = find_bucket(ti, hash); 7138c2ecf20Sopenharmony_ci (*n_mask_hit)++; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver], 7168c2ecf20Sopenharmony_ci lockdep_ovsl_is_held()) { 7178c2ecf20Sopenharmony_ci if (flow->mask == mask && flow->flow_table.hash == hash && 7188c2ecf20Sopenharmony_ci flow_cmp_masked_key(flow, &masked_key, &mask->range)) 7198c2ecf20Sopenharmony_ci return flow; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci return NULL; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/* Flow lookup does full lookup on flow table. It starts with 7258c2ecf20Sopenharmony_ci * mask from index passed in *index. 7268c2ecf20Sopenharmony_ci * This function MUST be called with BH disabled due to the use 7278c2ecf20Sopenharmony_ci * of CPU specific variables. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_cistatic struct sw_flow *flow_lookup(struct flow_table *tbl, 7308c2ecf20Sopenharmony_ci struct table_instance *ti, 7318c2ecf20Sopenharmony_ci struct mask_array *ma, 7328c2ecf20Sopenharmony_ci const struct sw_flow_key *key, 7338c2ecf20Sopenharmony_ci u32 *n_mask_hit, 7348c2ecf20Sopenharmony_ci u32 *n_cache_hit, 7358c2ecf20Sopenharmony_ci u32 *index) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct mask_array_stats *stats = this_cpu_ptr(ma->masks_usage_stats); 7388c2ecf20Sopenharmony_ci struct sw_flow *flow; 7398c2ecf20Sopenharmony_ci struct sw_flow_mask *mask; 7408c2ecf20Sopenharmony_ci int i; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (likely(*index < ma->max)) { 7438c2ecf20Sopenharmony_ci mask = rcu_dereference_ovsl(ma->masks[*index]); 7448c2ecf20Sopenharmony_ci if (mask) { 7458c2ecf20Sopenharmony_ci flow = masked_flow_lookup(ti, key, mask, n_mask_hit); 7468c2ecf20Sopenharmony_ci if (flow) { 7478c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 7488c2ecf20Sopenharmony_ci stats->usage_cntrs[*index]++; 7498c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 7508c2ecf20Sopenharmony_ci (*n_cache_hit)++; 7518c2ecf20Sopenharmony_ci return flow; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci for (i = 0; i < ma->max; i++) { 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (i == *index) 7598c2ecf20Sopenharmony_ci continue; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci mask = rcu_dereference_ovsl(ma->masks[i]); 7628c2ecf20Sopenharmony_ci if (unlikely(!mask)) 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci flow = masked_flow_lookup(ti, key, mask, n_mask_hit); 7668c2ecf20Sopenharmony_ci if (flow) { /* Found */ 7678c2ecf20Sopenharmony_ci *index = i; 7688c2ecf20Sopenharmony_ci u64_stats_update_begin(&stats->syncp); 7698c2ecf20Sopenharmony_ci stats->usage_cntrs[*index]++; 7708c2ecf20Sopenharmony_ci u64_stats_update_end(&stats->syncp); 7718c2ecf20Sopenharmony_ci return flow; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return NULL; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/* 7798c2ecf20Sopenharmony_ci * mask_cache maps flow to probable mask. This cache is not tightly 7808c2ecf20Sopenharmony_ci * coupled cache, It means updates to mask list can result in inconsistent 7818c2ecf20Sopenharmony_ci * cache entry in mask cache. 7828c2ecf20Sopenharmony_ci * This is per cpu cache and is divided in MC_HASH_SEGS segments. 7838c2ecf20Sopenharmony_ci * In case of a hash collision the entry is hashed in next segment. 7848c2ecf20Sopenharmony_ci * */ 7858c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, 7868c2ecf20Sopenharmony_ci const struct sw_flow_key *key, 7878c2ecf20Sopenharmony_ci u32 skb_hash, 7888c2ecf20Sopenharmony_ci u32 *n_mask_hit, 7898c2ecf20Sopenharmony_ci u32 *n_cache_hit) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct mask_cache *mc = rcu_dereference(tbl->mask_cache); 7928c2ecf20Sopenharmony_ci struct mask_array *ma = rcu_dereference(tbl->mask_array); 7938c2ecf20Sopenharmony_ci struct table_instance *ti = rcu_dereference(tbl->ti); 7948c2ecf20Sopenharmony_ci struct mask_cache_entry *entries, *ce; 7958c2ecf20Sopenharmony_ci struct sw_flow *flow; 7968c2ecf20Sopenharmony_ci u32 hash; 7978c2ecf20Sopenharmony_ci int seg; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci *n_mask_hit = 0; 8008c2ecf20Sopenharmony_ci *n_cache_hit = 0; 8018c2ecf20Sopenharmony_ci if (unlikely(!skb_hash || mc->cache_size == 0)) { 8028c2ecf20Sopenharmony_ci u32 mask_index = 0; 8038c2ecf20Sopenharmony_ci u32 cache = 0; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return flow_lookup(tbl, ti, ma, key, n_mask_hit, &cache, 8068c2ecf20Sopenharmony_ci &mask_index); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Pre and post recirulation flows usually have the same skb_hash 8108c2ecf20Sopenharmony_ci * value. To avoid hash collisions, rehash the 'skb_hash' with 8118c2ecf20Sopenharmony_ci * 'recirc_id'. */ 8128c2ecf20Sopenharmony_ci if (key->recirc_id) 8138c2ecf20Sopenharmony_ci skb_hash = jhash_1word(skb_hash, key->recirc_id); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci ce = NULL; 8168c2ecf20Sopenharmony_ci hash = skb_hash; 8178c2ecf20Sopenharmony_ci entries = this_cpu_ptr(mc->mask_cache); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Find the cache entry 'ce' to operate on. */ 8208c2ecf20Sopenharmony_ci for (seg = 0; seg < MC_HASH_SEGS; seg++) { 8218c2ecf20Sopenharmony_ci int index = hash & (mc->cache_size - 1); 8228c2ecf20Sopenharmony_ci struct mask_cache_entry *e; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci e = &entries[index]; 8258c2ecf20Sopenharmony_ci if (e->skb_hash == skb_hash) { 8268c2ecf20Sopenharmony_ci flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, 8278c2ecf20Sopenharmony_ci n_cache_hit, &e->mask_index); 8288c2ecf20Sopenharmony_ci if (!flow) 8298c2ecf20Sopenharmony_ci e->skb_hash = 0; 8308c2ecf20Sopenharmony_ci return flow; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (!ce || e->skb_hash < ce->skb_hash) 8348c2ecf20Sopenharmony_ci ce = e; /* A better replacement cache candidate. */ 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci hash >>= MC_HASH_SHIFT; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* Cache miss, do full lookup. */ 8408c2ecf20Sopenharmony_ci flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, n_cache_hit, 8418c2ecf20Sopenharmony_ci &ce->mask_index); 8428c2ecf20Sopenharmony_ci if (flow) 8438c2ecf20Sopenharmony_ci ce->skb_hash = skb_hash; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci *n_cache_hit = 0; 8468c2ecf20Sopenharmony_ci return flow; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 8508c2ecf20Sopenharmony_ci const struct sw_flow_key *key) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 8538c2ecf20Sopenharmony_ci struct mask_array *ma = rcu_dereference_ovsl(tbl->mask_array); 8548c2ecf20Sopenharmony_ci u32 __always_unused n_mask_hit; 8558c2ecf20Sopenharmony_ci u32 __always_unused n_cache_hit; 8568c2ecf20Sopenharmony_ci struct sw_flow *flow; 8578c2ecf20Sopenharmony_ci u32 index = 0; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* This function gets called trough the netlink interface and therefore 8608c2ecf20Sopenharmony_ci * is preemptible. However, flow_lookup() function needs to be called 8618c2ecf20Sopenharmony_ci * with BH disabled due to CPU specific variables. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_ci local_bh_disable(); 8648c2ecf20Sopenharmony_ci flow = flow_lookup(tbl, ti, ma, key, &n_mask_hit, &n_cache_hit, &index); 8658c2ecf20Sopenharmony_ci local_bh_enable(); 8668c2ecf20Sopenharmony_ci return flow; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl, 8708c2ecf20Sopenharmony_ci const struct sw_flow_match *match) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci struct mask_array *ma = ovsl_dereference(tbl->mask_array); 8738c2ecf20Sopenharmony_ci int i; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Always called under ovs-mutex. */ 8768c2ecf20Sopenharmony_ci for (i = 0; i < ma->max; i++) { 8778c2ecf20Sopenharmony_ci struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 8788c2ecf20Sopenharmony_ci u32 __always_unused n_mask_hit; 8798c2ecf20Sopenharmony_ci struct sw_flow_mask *mask; 8808c2ecf20Sopenharmony_ci struct sw_flow *flow; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci mask = ovsl_dereference(ma->masks[i]); 8838c2ecf20Sopenharmony_ci if (!mask) 8848c2ecf20Sopenharmony_ci continue; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci flow = masked_flow_lookup(ti, match->key, mask, &n_mask_hit); 8878c2ecf20Sopenharmony_ci if (flow && ovs_identifier_is_key(&flow->id) && 8888c2ecf20Sopenharmony_ci ovs_flow_cmp_unmasked_key(flow, match)) { 8898c2ecf20Sopenharmony_ci return flow; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci return NULL; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic u32 ufid_hash(const struct sw_flow_id *sfid) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci return jhash(sfid->ufid, sfid->ufid_len, 0); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic bool ovs_flow_cmp_ufid(const struct sw_flow *flow, 9028c2ecf20Sopenharmony_ci const struct sw_flow_id *sfid) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci if (flow->id.ufid_len != sfid->ufid_len) 9058c2ecf20Sopenharmony_ci return false; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return !memcmp(flow->id.ufid, sfid->ufid, sfid->ufid_len); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cibool ovs_flow_cmp(const struct sw_flow *flow, 9118c2ecf20Sopenharmony_ci const struct sw_flow_match *match) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci if (ovs_identifier_is_ufid(&flow->id)) 9148c2ecf20Sopenharmony_ci return flow_cmp_masked_key(flow, match->key, &match->range); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return ovs_flow_cmp_unmasked_key(flow, match); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistruct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *tbl, 9208c2ecf20Sopenharmony_ci const struct sw_flow_id *ufid) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct table_instance *ti = rcu_dereference_ovsl(tbl->ufid_ti); 9238c2ecf20Sopenharmony_ci struct sw_flow *flow; 9248c2ecf20Sopenharmony_ci struct hlist_head *head; 9258c2ecf20Sopenharmony_ci u32 hash; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci hash = ufid_hash(ufid); 9288c2ecf20Sopenharmony_ci head = find_bucket(ti, hash); 9298c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(flow, head, ufid_table.node[ti->node_ver], 9308c2ecf20Sopenharmony_ci lockdep_ovsl_is_held()) { 9318c2ecf20Sopenharmony_ci if (flow->ufid_table.hash == hash && 9328c2ecf20Sopenharmony_ci ovs_flow_cmp_ufid(flow, ufid)) 9338c2ecf20Sopenharmony_ci return flow; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci return NULL; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ciint ovs_flow_tbl_num_masks(const struct flow_table *table) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct mask_array *ma = rcu_dereference_ovsl(table->mask_array); 9418c2ecf20Sopenharmony_ci return READ_ONCE(ma->count); 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciu32 ovs_flow_tbl_masks_cache_size(const struct flow_table *table) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct mask_cache *mc = rcu_dereference_ovsl(table->mask_cache); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return READ_ONCE(mc->cache_size); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic struct table_instance *table_instance_expand(struct table_instance *ti, 9528c2ecf20Sopenharmony_ci bool ufid) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci return table_instance_rehash(ti, ti->n_buckets * 2, ufid); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 9588c2ecf20Sopenharmony_civoid ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct table_instance *ti = ovsl_dereference(table->ti); 9618c2ecf20Sopenharmony_ci struct table_instance *ufid_ti = ovsl_dereference(table->ufid_ti); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci BUG_ON(table->count == 0); 9648c2ecf20Sopenharmony_ci table_instance_flow_free(table, ti, ufid_ti, flow); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic struct sw_flow_mask *mask_alloc(void) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct sw_flow_mask *mask; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci mask = kmalloc(sizeof(*mask), GFP_KERNEL); 9728c2ecf20Sopenharmony_ci if (mask) 9738c2ecf20Sopenharmony_ci mask->ref_count = 1; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci return mask; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic bool mask_equal(const struct sw_flow_mask *a, 9798c2ecf20Sopenharmony_ci const struct sw_flow_mask *b) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci const u8 *a_ = (const u8 *)&a->key + a->range.start; 9828c2ecf20Sopenharmony_ci const u8 *b_ = (const u8 *)&b->key + b->range.start; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci return (a->range.end == b->range.end) 9858c2ecf20Sopenharmony_ci && (a->range.start == b->range.start) 9868c2ecf20Sopenharmony_ci && (memcmp(a_, b_, range_n_bytes(&a->range)) == 0); 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl, 9908c2ecf20Sopenharmony_ci const struct sw_flow_mask *mask) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct mask_array *ma; 9938c2ecf20Sopenharmony_ci int i; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci ma = ovsl_dereference(tbl->mask_array); 9968c2ecf20Sopenharmony_ci for (i = 0; i < ma->max; i++) { 9978c2ecf20Sopenharmony_ci struct sw_flow_mask *t; 9988c2ecf20Sopenharmony_ci t = ovsl_dereference(ma->masks[i]); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (t && mask_equal(mask, t)) 10018c2ecf20Sopenharmony_ci return t; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return NULL; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/* Add 'mask' into the mask list, if it is not already there. */ 10088c2ecf20Sopenharmony_cistatic int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, 10098c2ecf20Sopenharmony_ci const struct sw_flow_mask *new) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct sw_flow_mask *mask; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci mask = flow_mask_find(tbl, new); 10148c2ecf20Sopenharmony_ci if (!mask) { 10158c2ecf20Sopenharmony_ci /* Allocate a new mask if none exsits. */ 10168c2ecf20Sopenharmony_ci mask = mask_alloc(); 10178c2ecf20Sopenharmony_ci if (!mask) 10188c2ecf20Sopenharmony_ci return -ENOMEM; 10198c2ecf20Sopenharmony_ci mask->key = new->key; 10208c2ecf20Sopenharmony_ci mask->range = new->range; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* Add mask to mask-list. */ 10238c2ecf20Sopenharmony_ci if (tbl_mask_array_add_mask(tbl, mask)) { 10248c2ecf20Sopenharmony_ci kfree(mask); 10258c2ecf20Sopenharmony_ci return -ENOMEM; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci } else { 10288c2ecf20Sopenharmony_ci BUG_ON(!mask->ref_count); 10298c2ecf20Sopenharmony_ci mask->ref_count++; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci flow->mask = mask; 10338c2ecf20Sopenharmony_ci return 0; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 10378c2ecf20Sopenharmony_cistatic void flow_key_insert(struct flow_table *table, struct sw_flow *flow) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct table_instance *new_ti = NULL; 10408c2ecf20Sopenharmony_ci struct table_instance *ti; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci flow->flow_table.hash = flow_hash(&flow->key, &flow->mask->range); 10438c2ecf20Sopenharmony_ci ti = ovsl_dereference(table->ti); 10448c2ecf20Sopenharmony_ci table_instance_insert(ti, flow); 10458c2ecf20Sopenharmony_ci table->count++; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* Expand table, if necessary, to make room. */ 10488c2ecf20Sopenharmony_ci if (table->count > ti->n_buckets) 10498c2ecf20Sopenharmony_ci new_ti = table_instance_expand(ti, false); 10508c2ecf20Sopenharmony_ci else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL)) 10518c2ecf20Sopenharmony_ci new_ti = table_instance_rehash(ti, ti->n_buckets, false); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (new_ti) { 10548c2ecf20Sopenharmony_ci rcu_assign_pointer(table->ti, new_ti); 10558c2ecf20Sopenharmony_ci call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb); 10568c2ecf20Sopenharmony_ci table->last_rehash = jiffies; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 10618c2ecf20Sopenharmony_cistatic void flow_ufid_insert(struct flow_table *table, struct sw_flow *flow) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct table_instance *ti; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci flow->ufid_table.hash = ufid_hash(&flow->id); 10668c2ecf20Sopenharmony_ci ti = ovsl_dereference(table->ufid_ti); 10678c2ecf20Sopenharmony_ci ufid_table_instance_insert(ti, flow); 10688c2ecf20Sopenharmony_ci table->ufid_count++; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* Expand table, if necessary, to make room. */ 10718c2ecf20Sopenharmony_ci if (table->ufid_count > ti->n_buckets) { 10728c2ecf20Sopenharmony_ci struct table_instance *new_ti; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci new_ti = table_instance_expand(ti, true); 10758c2ecf20Sopenharmony_ci if (new_ti) { 10768c2ecf20Sopenharmony_ci rcu_assign_pointer(table->ufid_ti, new_ti); 10778c2ecf20Sopenharmony_ci call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 10838c2ecf20Sopenharmony_ciint ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, 10848c2ecf20Sopenharmony_ci const struct sw_flow_mask *mask) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci int err; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci err = flow_mask_insert(table, flow, mask); 10898c2ecf20Sopenharmony_ci if (err) 10908c2ecf20Sopenharmony_ci return err; 10918c2ecf20Sopenharmony_ci flow_key_insert(table, flow); 10928c2ecf20Sopenharmony_ci if (ovs_identifier_is_ufid(&flow->id)) 10938c2ecf20Sopenharmony_ci flow_ufid_insert(table, flow); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int compare_mask_and_count(const void *a, const void *b) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci const struct mask_count *mc_a = a; 11018c2ecf20Sopenharmony_ci const struct mask_count *mc_b = b; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return (s64)mc_b->counter - (s64)mc_a->counter; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci/* Must be called with OVS mutex held. */ 11078c2ecf20Sopenharmony_civoid ovs_flow_masks_rebalance(struct flow_table *table) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci struct mask_array *ma = rcu_dereference_ovsl(table->mask_array); 11108c2ecf20Sopenharmony_ci struct mask_count *masks_and_count; 11118c2ecf20Sopenharmony_ci struct mask_array *new; 11128c2ecf20Sopenharmony_ci int masks_entries = 0; 11138c2ecf20Sopenharmony_ci int i; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* Build array of all current entries with use counters. */ 11168c2ecf20Sopenharmony_ci masks_and_count = kmalloc_array(ma->max, sizeof(*masks_and_count), 11178c2ecf20Sopenharmony_ci GFP_KERNEL); 11188c2ecf20Sopenharmony_ci if (!masks_and_count) 11198c2ecf20Sopenharmony_ci return; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci for (i = 0; i < ma->max; i++) { 11228c2ecf20Sopenharmony_ci struct sw_flow_mask *mask; 11238c2ecf20Sopenharmony_ci int cpu; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci mask = rcu_dereference_ovsl(ma->masks[i]); 11268c2ecf20Sopenharmony_ci if (unlikely(!mask)) 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci masks_and_count[i].index = i; 11308c2ecf20Sopenharmony_ci masks_and_count[i].counter = 0; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 11338c2ecf20Sopenharmony_ci struct mask_array_stats *stats; 11348c2ecf20Sopenharmony_ci unsigned int start; 11358c2ecf20Sopenharmony_ci u64 counter; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci stats = per_cpu_ptr(ma->masks_usage_stats, cpu); 11388c2ecf20Sopenharmony_ci do { 11398c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&stats->syncp); 11408c2ecf20Sopenharmony_ci counter = stats->usage_cntrs[i]; 11418c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&stats->syncp, 11428c2ecf20Sopenharmony_ci start)); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci masks_and_count[i].counter += counter; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* Subtract the zero count value. */ 11488c2ecf20Sopenharmony_ci masks_and_count[i].counter -= ma->masks_usage_zero_cntr[i]; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* Rather than calling tbl_mask_array_reset_counters() 11518c2ecf20Sopenharmony_ci * below when no change is needed, do it inline here. 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_ci ma->masks_usage_zero_cntr[i] += masks_and_count[i].counter; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (i == 0) 11578c2ecf20Sopenharmony_ci goto free_mask_entries; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Sort the entries */ 11608c2ecf20Sopenharmony_ci masks_entries = i; 11618c2ecf20Sopenharmony_ci sort(masks_and_count, masks_entries, sizeof(*masks_and_count), 11628c2ecf20Sopenharmony_ci compare_mask_and_count, NULL); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* If the order is the same, nothing to do... */ 11658c2ecf20Sopenharmony_ci for (i = 0; i < masks_entries; i++) { 11668c2ecf20Sopenharmony_ci if (i != masks_and_count[i].index) 11678c2ecf20Sopenharmony_ci break; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci if (i == masks_entries) 11708c2ecf20Sopenharmony_ci goto free_mask_entries; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Rebuilt the new list in order of usage. */ 11738c2ecf20Sopenharmony_ci new = tbl_mask_array_alloc(ma->max); 11748c2ecf20Sopenharmony_ci if (!new) 11758c2ecf20Sopenharmony_ci goto free_mask_entries; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci for (i = 0; i < masks_entries; i++) { 11788c2ecf20Sopenharmony_ci int index = masks_and_count[i].index; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (ovsl_dereference(ma->masks[index])) 11818c2ecf20Sopenharmony_ci new->masks[new->count++] = ma->masks[index]; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci rcu_assign_pointer(table->mask_array, new); 11858c2ecf20Sopenharmony_ci call_rcu(&ma->rcu, mask_array_rcu_cb); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cifree_mask_entries: 11888c2ecf20Sopenharmony_ci kfree(masks_and_count); 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci/* Initializes the flow module. 11928c2ecf20Sopenharmony_ci * Returns zero if successful or a negative error code. */ 11938c2ecf20Sopenharmony_ciint ovs_flow_init(void) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci BUILD_BUG_ON(__alignof__(struct sw_flow_key) % __alignof__(long)); 11968c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long)); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow) 11998c2ecf20Sopenharmony_ci + (nr_cpu_ids 12008c2ecf20Sopenharmony_ci * sizeof(struct sw_flow_stats *)), 12018c2ecf20Sopenharmony_ci 0, 0, NULL); 12028c2ecf20Sopenharmony_ci if (flow_cache == NULL) 12038c2ecf20Sopenharmony_ci return -ENOMEM; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci flow_stats_cache 12068c2ecf20Sopenharmony_ci = kmem_cache_create("sw_flow_stats", sizeof(struct sw_flow_stats), 12078c2ecf20Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, NULL); 12088c2ecf20Sopenharmony_ci if (flow_stats_cache == NULL) { 12098c2ecf20Sopenharmony_ci kmem_cache_destroy(flow_cache); 12108c2ecf20Sopenharmony_ci flow_cache = NULL; 12118c2ecf20Sopenharmony_ci return -ENOMEM; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci return 0; 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci/* Uninitializes the flow module. */ 12188c2ecf20Sopenharmony_civoid ovs_flow_exit(void) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci kmem_cache_destroy(flow_stats_cache); 12218c2ecf20Sopenharmony_ci kmem_cache_destroy(flow_cache); 12228c2ecf20Sopenharmony_ci} 1223