flow_table.c (04b7d136d015f220b1003e6c573834658d507a31) | flow_table.c (4bc63b1b531df518576a97d17bf5939fdbc33ccb) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2007-2014 Nicira, Inc. 4 */ 5 6#include "flow.h" 7#include "datapath.h" 8#include "flow_netlink.h" --- 20 unchanged lines hidden (view full) --- 29#include <linux/icmp.h> 30#include <linux/icmpv6.h> 31#include <linux/rculist.h> 32#include <net/ip.h> 33#include <net/ipv6.h> 34#include <net/ndisc.h> 35 36#define TBL_MIN_BUCKETS 1024 | 1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2007-2014 Nicira, Inc. 4 */ 5 6#include "flow.h" 7#include "datapath.h" 8#include "flow_netlink.h" --- 20 unchanged lines hidden (view full) --- 29#include <linux/icmp.h> 30#include <linux/icmpv6.h> 31#include <linux/rculist.h> 32#include <net/ip.h> 33#include <net/ipv6.h> 34#include <net/ndisc.h> 35 36#define TBL_MIN_BUCKETS 1024 |
37#define MASK_ARRAY_SIZE_MIN 16 |
|
37#define REHASH_INTERVAL (10 * 60 * HZ) 38 39#define MC_HASH_SHIFT 8 40#define MC_HASH_ENTRIES (1u << MC_HASH_SHIFT) 41#define MC_HASH_SEGS ((sizeof(uint32_t) * 8) / MC_HASH_SHIFT) 42 43static struct kmem_cache *flow_cache; 44struct kmem_cache *flow_stats_cache __read_mostly; --- 118 unchanged lines hidden (view full) --- 163 ti->n_buckets = new_size; 164 ti->node_ver = 0; 165 ti->keep_flows = false; 166 get_random_bytes(&ti->hash_seed, sizeof(u32)); 167 168 return ti; 169} 170 | 38#define REHASH_INTERVAL (10 * 60 * HZ) 39 40#define MC_HASH_SHIFT 8 41#define MC_HASH_ENTRIES (1u << MC_HASH_SHIFT) 42#define MC_HASH_SEGS ((sizeof(uint32_t) * 8) / MC_HASH_SHIFT) 43 44static struct kmem_cache *flow_cache; 45struct kmem_cache *flow_stats_cache __read_mostly; --- 118 unchanged lines hidden (view full) --- 164 ti->n_buckets = new_size; 165 ti->node_ver = 0; 166 ti->keep_flows = false; 167 get_random_bytes(&ti->hash_seed, sizeof(u32)); 168 169 return ti; 170} 171 |
172static struct mask_array *tbl_mask_array_alloc(int size) 173{ 174 struct mask_array *new; 175 176 size = max(MASK_ARRAY_SIZE_MIN, size); 177 new = kzalloc(sizeof(struct mask_array) + 178 sizeof(struct sw_flow_mask *) * size, GFP_KERNEL); 179 if (!new) 180 return NULL; 181 182 new->count = 0; 183 new->max = size; 184 185 return new; 186} 187 188static int tbl_mask_array_realloc(struct flow_table *tbl, int size) 189{ 190 struct mask_array *old; 191 struct mask_array *new; 192 193 new = tbl_mask_array_alloc(size); 194 if (!new) 195 return -ENOMEM; 196 197 old = ovsl_dereference(tbl->mask_array); 198 if (old) { 199 int i; 200 201 for (i = 0; i < old->max; i++) { 202 if (ovsl_dereference(old->masks[i])) 203 new->masks[new->count++] = old->masks[i]; 204 } 205 } 206 207 rcu_assign_pointer(tbl->mask_array, new); 208 kfree_rcu(old, rcu); 209 210 return 0; 211} 212 |
|
171int ovs_flow_tbl_init(struct flow_table *table) 172{ 173 struct table_instance *ti, *ufid_ti; | 213int ovs_flow_tbl_init(struct flow_table *table) 214{ 215 struct table_instance *ti, *ufid_ti; |
216 struct mask_array *ma; |
|
174 175 table->mask_cache = __alloc_percpu(sizeof(struct mask_cache_entry) * 176 MC_HASH_ENTRIES, 177 __alignof__(struct mask_cache_entry)); 178 if (!table->mask_cache) 179 return -ENOMEM; 180 | 217 218 table->mask_cache = __alloc_percpu(sizeof(struct mask_cache_entry) * 219 MC_HASH_ENTRIES, 220 __alignof__(struct mask_cache_entry)); 221 if (!table->mask_cache) 222 return -ENOMEM; 223 |
224 ma = tbl_mask_array_alloc(MASK_ARRAY_SIZE_MIN); 225 if (!ma) 226 goto free_mask_cache; 227 |
|
181 ti = table_instance_alloc(TBL_MIN_BUCKETS); 182 if (!ti) | 228 ti = table_instance_alloc(TBL_MIN_BUCKETS); 229 if (!ti) |
183 goto free_mask_cache; | 230 goto free_mask_array; |
184 185 ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS); 186 if (!ufid_ti) 187 goto free_ti; 188 189 rcu_assign_pointer(table->ti, ti); 190 rcu_assign_pointer(table->ufid_ti, ufid_ti); | 231 232 ufid_ti = table_instance_alloc(TBL_MIN_BUCKETS); 233 if (!ufid_ti) 234 goto free_ti; 235 236 rcu_assign_pointer(table->ti, ti); 237 rcu_assign_pointer(table->ufid_ti, ufid_ti); |
191 INIT_LIST_HEAD(&table->mask_list); | 238 rcu_assign_pointer(table->mask_array, ma); |
192 table->last_rehash = jiffies; 193 table->count = 0; 194 table->ufid_count = 0; 195 return 0; 196 197free_ti: 198 __table_instance_destroy(ti); | 239 table->last_rehash = jiffies; 240 table->count = 0; 241 table->ufid_count = 0; 242 return 0; 243 244free_ti: 245 __table_instance_destroy(ti); |
246free_mask_array: 247 kfree(ma); |
|
199free_mask_cache: 200 free_percpu(table->mask_cache); 201 return -ENOMEM; 202} 203 204static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu) 205{ 206 struct table_instance *ti = container_of(rcu, struct table_instance, rcu); --- 43 unchanged lines hidden (view full) --- 250 * error path. 251 */ 252void ovs_flow_tbl_destroy(struct flow_table *table) 253{ 254 struct table_instance *ti = rcu_dereference_raw(table->ti); 255 struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti); 256 257 free_percpu(table->mask_cache); | 248free_mask_cache: 249 free_percpu(table->mask_cache); 250 return -ENOMEM; 251} 252 253static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu) 254{ 255 struct table_instance *ti = container_of(rcu, struct table_instance, rcu); --- 43 unchanged lines hidden (view full) --- 299 * error path. 300 */ 301void ovs_flow_tbl_destroy(struct flow_table *table) 302{ 303 struct table_instance *ti = rcu_dereference_raw(table->ti); 304 struct table_instance *ufid_ti = rcu_dereference_raw(table->ufid_ti); 305 306 free_percpu(table->mask_cache); |
307 kfree_rcu(rcu_dereference_raw(table->mask_array), rcu); |
|
258 table_instance_destroy(ti, ufid_ti, false); 259} 260 261struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, 262 u32 *bucket, u32 *last) 263{ 264 struct sw_flow *flow; 265 struct hlist_head *head; --- 189 unchanged lines hidden (view full) --- 455 flow_cmp_masked_key(flow, &masked_key, &mask->range)) 456 return flow; 457 } 458 return NULL; 459} 460 461static struct sw_flow *flow_lookup(struct flow_table *tbl, 462 struct table_instance *ti, | 308 table_instance_destroy(ti, ufid_ti, false); 309} 310 311struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti, 312 u32 *bucket, u32 *last) 313{ 314 struct sw_flow *flow; 315 struct hlist_head *head; --- 189 unchanged lines hidden (view full) --- 505 flow_cmp_masked_key(flow, &masked_key, &mask->range)) 506 return flow; 507 } 508 return NULL; 509} 510 511static struct sw_flow *flow_lookup(struct flow_table *tbl, 512 struct table_instance *ti, |
513 struct mask_array *ma, |
|
463 const struct sw_flow_key *key, | 514 const struct sw_flow_key *key, |
464 u32 *n_mask_hit) | 515 u32 *n_mask_hit, 516 u32 *index) |
465{ | 517{ |
466 struct sw_flow_mask *mask; | |
467 struct sw_flow *flow; | 518 struct sw_flow *flow; |
519 int i; |
|
468 | 520 |
469 list_for_each_entry_rcu(mask, &tbl->mask_list, list) { 470 flow = masked_flow_lookup(ti, key, mask, n_mask_hit); 471 if (flow) /* Found */ 472 return flow; | 521 for (i = 0; i < ma->max; i++) { 522 struct sw_flow_mask *mask; 523 524 mask = rcu_dereference_ovsl(ma->masks[i]); 525 if (mask) { 526 flow = masked_flow_lookup(ti, key, mask, n_mask_hit); 527 if (flow) { /* Found */ 528 *index = i; 529 return flow; 530 } 531 } |
473 } | 532 } |
533 |
|
474 return NULL; 475} 476 477/* 478 * mask_cache maps flow to probable mask. This cache is not tightly 479 * coupled cache, It means updates to mask list can result in inconsistent 480 * cache entry in mask cache. 481 * This is per cpu cache and is divided in MC_HASH_SEGS segments. 482 * In case of a hash collision the entry is hashed in next segment. 483 * */ 484struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, 485 const struct sw_flow_key *key, 486 u32 skb_hash, 487 u32 *n_mask_hit) 488{ | 534 return NULL; 535} 536 537/* 538 * mask_cache maps flow to probable mask. This cache is not tightly 539 * coupled cache, It means updates to mask list can result in inconsistent 540 * cache entry in mask cache. 541 * This is per cpu cache and is divided in MC_HASH_SEGS segments. 542 * In case of a hash collision the entry is hashed in next segment. 543 * */ 544struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, 545 const struct sw_flow_key *key, 546 u32 skb_hash, 547 u32 *n_mask_hit) 548{ |
549 struct mask_array *ma = rcu_dereference_ovsl(tbl->mask_array); |
|
489 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 490 struct mask_cache_entry *entries, *ce, *del; 491 struct sw_flow *flow; 492 u32 hash = skb_hash; 493 int seg; 494 495 *n_mask_hit = 0; | 550 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 551 struct mask_cache_entry *entries, *ce, *del; 552 struct sw_flow *flow; 553 u32 hash = skb_hash; 554 int seg; 555 556 *n_mask_hit = 0; |
496 if (unlikely(!skb_hash)) 497 return flow_lookup(tbl, ti, key, n_mask_hit); | 557 if (unlikely(!skb_hash)) { 558 u32 __always_unused mask_index; |
498 | 559 |
560 return flow_lookup(tbl, ti, ma, key, n_mask_hit, &mask_index); 561 } 562 |
|
499 del = NULL; 500 entries = this_cpu_ptr(tbl->mask_cache); 501 502 for (seg = 0; seg < MC_HASH_SEGS; seg++) { 503 int index; 504 505 index = hash & (MC_HASH_ENTRIES - 1); 506 ce = &entries[index]; 507 508 if (ce->skb_hash == skb_hash) { 509 struct sw_flow_mask *mask; | 563 del = NULL; 564 entries = this_cpu_ptr(tbl->mask_cache); 565 566 for (seg = 0; seg < MC_HASH_SEGS; seg++) { 567 int index; 568 569 index = hash & (MC_HASH_ENTRIES - 1); 570 ce = &entries[index]; 571 572 if (ce->skb_hash == skb_hash) { 573 struct sw_flow_mask *mask; |
510 int i; | 574 struct sw_flow *flow; |
511 | 575 |
512 i = 0; 513 list_for_each_entry_rcu(mask, &tbl->mask_list, list) { 514 if (ce->mask_index == i++) { 515 flow = masked_flow_lookup(ti, key, mask, 516 n_mask_hit); 517 if (flow) /* Found */ 518 return flow; 519 520 break; 521 } | 576 mask = rcu_dereference_ovsl(ma->masks[ce->mask_index]); 577 if (mask) { 578 flow = masked_flow_lookup(ti, key, mask, 579 n_mask_hit); 580 if (flow) /* Found */ 581 return flow; |
522 } 523 524 del = ce; 525 break; 526 } 527 | 582 } 583 584 del = ce; 585 break; 586 } 587 |
528 if (!del || (del->skb_hash && !ce->skb_hash)) { | 588 if (!del || (del->skb_hash && !ce->skb_hash) || 589 (rcu_dereference_ovsl(ma->masks[del->mask_index]) && 590 !rcu_dereference_ovsl(ma->masks[ce->mask_index]))) { |
529 del = ce; 530 } 531 532 hash >>= MC_HASH_SHIFT; 533 } 534 | 591 del = ce; 592 } 593 594 hash >>= MC_HASH_SHIFT; 595 } 596 |
535 flow = flow_lookup(tbl, ti, key, n_mask_hit); | 597 flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &del->mask_index); |
536 | 598 |
537 if (flow) { | 599 if (flow) |
538 del->skb_hash = skb_hash; | 600 del->skb_hash = skb_hash; |
539 del->mask_index = (*n_mask_hit - 1); 540 } | |
541 542 return flow; 543} 544 545struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 546 const struct sw_flow_key *key) 547{ 548 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); | 601 602 return flow; 603} 604 605struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 606 const struct sw_flow_key *key) 607{ 608 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); |
609 struct mask_array *ma = rcu_dereference_ovsl(tbl->mask_array); 610 |
|
549 u32 __always_unused n_mask_hit; | 611 u32 __always_unused n_mask_hit; |
612 u32 __always_unused index; |
|
550 | 613 |
551 return flow_lookup(tbl, ti, key, &n_mask_hit); | 614 return flow_lookup(tbl, ti, ma, key, &n_mask_hit, &index); |
552} 553 554struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl, 555 const struct sw_flow_match *match) 556{ | 615} 616 617struct sw_flow *ovs_flow_tbl_lookup_exact(struct flow_table *tbl, 618 const struct sw_flow_match *match) 619{ |
557 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 558 struct sw_flow_mask *mask; 559 struct sw_flow *flow; 560 u32 __always_unused n_mask_hit; | 620 struct mask_array *ma = ovsl_dereference(tbl->mask_array); 621 int i; |
561 562 /* Always called under ovs-mutex. */ | 622 623 /* Always called under ovs-mutex. */ |
563 list_for_each_entry(mask, &tbl->mask_list, list) { | 624 for (i = 0; i < ma->max; i++) { 625 struct table_instance *ti = rcu_dereference_ovsl(tbl->ti); 626 u32 __always_unused n_mask_hit; 627 struct sw_flow_mask *mask; 628 struct sw_flow *flow; 629 630 mask = ovsl_dereference(ma->masks[i]); 631 if (!mask) 632 continue; 633 |
564 flow = masked_flow_lookup(ti, match->key, mask, &n_mask_hit); 565 if (flow && ovs_identifier_is_key(&flow->id) && | 634 flow = masked_flow_lookup(ti, match->key, mask, &n_mask_hit); 635 if (flow && ovs_identifier_is_key(&flow->id) && |
566 ovs_flow_cmp_unmasked_key(flow, match)) | 636 ovs_flow_cmp_unmasked_key(flow, match)) { |
567 return flow; | 637 return flow; |
638 } |
|
568 } | 639 } |
640 |
|
569 return NULL; 570} 571 572static u32 ufid_hash(const struct sw_flow_id *sfid) 573{ 574 return jhash(sfid->ufid, sfid->ufid_len, 0); 575} 576 --- 29 unchanged lines hidden (view full) --- 606 ovs_flow_cmp_ufid(flow, ufid)) 607 return flow; 608 } 609 return NULL; 610} 611 612int ovs_flow_tbl_num_masks(const struct flow_table *table) 613{ | 641 return NULL; 642} 643 644static u32 ufid_hash(const struct sw_flow_id *sfid) 645{ 646 return jhash(sfid->ufid, sfid->ufid_len, 0); 647} 648 --- 29 unchanged lines hidden (view full) --- 678 ovs_flow_cmp_ufid(flow, ufid)) 679 return flow; 680 } 681 return NULL; 682} 683 684int ovs_flow_tbl_num_masks(const struct flow_table *table) 685{ |
614 struct sw_flow_mask *mask; 615 int num = 0; | 686 struct mask_array *ma = rcu_dereference_ovsl(table->mask_array); |
616 | 687 |
617 list_for_each_entry(mask, &table->mask_list, list) 618 num++; 619 620 return num; | 688 return ma->count; |
621} 622 623static struct table_instance *table_instance_expand(struct table_instance *ti, 624 bool ufid) 625{ 626 return table_instance_rehash(ti, ti->n_buckets * 2, ufid); 627} 628 --- 4 unchanged lines hidden (view full) --- 633 /* ovs-lock is required to protect mask-refcount and 634 * mask list. 635 */ 636 ASSERT_OVSL(); 637 BUG_ON(!mask->ref_count); 638 mask->ref_count--; 639 640 if (!mask->ref_count) { | 689} 690 691static struct table_instance *table_instance_expand(struct table_instance *ti, 692 bool ufid) 693{ 694 return table_instance_rehash(ti, ti->n_buckets * 2, ufid); 695} 696 --- 4 unchanged lines hidden (view full) --- 701 /* ovs-lock is required to protect mask-refcount and 702 * mask list. 703 */ 704 ASSERT_OVSL(); 705 BUG_ON(!mask->ref_count); 706 mask->ref_count--; 707 708 if (!mask->ref_count) { |
641 list_del_rcu(&mask->list); 642 kfree_rcu(mask, rcu); | 709 struct mask_array *ma; 710 int i; 711 712 ma = ovsl_dereference(tbl->mask_array); 713 for (i = 0; i < ma->max; i++) { 714 if (mask == ovsl_dereference(ma->masks[i])) { 715 RCU_INIT_POINTER(ma->masks[i], NULL); 716 ma->count--; 717 kfree_rcu(mask, rcu); 718 return; 719 } 720 } 721 BUG(); |
643 } 644 } 645} 646 647/* Must be called with OVS mutex held. */ 648void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) 649{ 650 struct table_instance *ti = ovsl_dereference(table->ti); --- 33 unchanged lines hidden (view full) --- 684 return (a->range.end == b->range.end) 685 && (a->range.start == b->range.start) 686 && (memcmp(a_, b_, range_n_bytes(&a->range)) == 0); 687} 688 689static struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl, 690 const struct sw_flow_mask *mask) 691{ | 722 } 723 } 724} 725 726/* Must be called with OVS mutex held. */ 727void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) 728{ 729 struct table_instance *ti = ovsl_dereference(table->ti); --- 33 unchanged lines hidden (view full) --- 763 return (a->range.end == b->range.end) 764 && (a->range.start == b->range.start) 765 && (memcmp(a_, b_, range_n_bytes(&a->range)) == 0); 766} 767 768static struct sw_flow_mask *flow_mask_find(const struct flow_table *tbl, 769 const struct sw_flow_mask *mask) 770{ |
692 struct list_head *ml; | 771 struct mask_array *ma; 772 int i; |
693 | 773 |
694 list_for_each(ml, &tbl->mask_list) { 695 struct sw_flow_mask *m; 696 m = container_of(ml, struct sw_flow_mask, list); 697 if (mask_equal(mask, m)) 698 return m; | 774 ma = ovsl_dereference(tbl->mask_array); 775 for (i = 0; i < ma->max; i++) { 776 struct sw_flow_mask *t; 777 t = ovsl_dereference(ma->masks[i]); 778 779 if (t && mask_equal(mask, t)) 780 return t; |
699 } 700 701 return NULL; 702} 703 704/* Add 'mask' into the mask list, if it is not already there. */ 705static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, 706 const struct sw_flow_mask *new) 707{ 708 struct sw_flow_mask *mask; | 781 } 782 783 return NULL; 784} 785 786/* Add 'mask' into the mask list, if it is not already there. */ 787static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow, 788 const struct sw_flow_mask *new) 789{ 790 struct sw_flow_mask *mask; |
791 |
|
709 mask = flow_mask_find(tbl, new); 710 if (!mask) { | 792 mask = flow_mask_find(tbl, new); 793 if (!mask) { |
794 struct mask_array *ma; 795 int i; 796 |
|
711 /* Allocate a new mask if none exsits. */ 712 mask = mask_alloc(); 713 if (!mask) 714 return -ENOMEM; 715 mask->key = new->key; 716 mask->range = new->range; | 797 /* Allocate a new mask if none exsits. */ 798 mask = mask_alloc(); 799 if (!mask) 800 return -ENOMEM; 801 mask->key = new->key; 802 mask->range = new->range; |
717 list_add_tail_rcu(&mask->list, &tbl->mask_list); | 803 804 /* Add mask to mask-list. */ 805 ma = ovsl_dereference(tbl->mask_array); 806 if (ma->count >= ma->max) { 807 int err; 808 809 err = tbl_mask_array_realloc(tbl, ma->max + 810 MASK_ARRAY_SIZE_MIN); 811 if (err) { 812 kfree(mask); 813 return err; 814 } 815 816 ma = ovsl_dereference(tbl->mask_array); 817 } 818 819 for (i = 0; i < ma->max; i++) { 820 const struct sw_flow_mask *t; 821 822 t = ovsl_dereference(ma->masks[i]); 823 if (!t) { 824 rcu_assign_pointer(ma->masks[i], mask); 825 ma->count++; 826 break; 827 } 828 } |
718 } else { 719 BUG_ON(!mask->ref_count); 720 mask->ref_count++; 721 } 722 723 flow->mask = mask; 724 return 0; 725} --- 95 unchanged lines hidden --- | 829 } else { 830 BUG_ON(!mask->ref_count); 831 mask->ref_count++; 832 } 833 834 flow->mask = mask; 835 return 0; 836} --- 95 unchanged lines hidden --- |