/* * Copyright (c) 2017-2019 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <vppinfra/error.h> u8 RT (rule_is_exact_match) (RTT (mma_rule) * key, RTT (mma_rule) * r) { int i; for (i = 0; i < ARRAY_LEN (key->match.as_u64); i++) { if (key->match.as_u64[i] != r->match.as_u64[i]) return 0; } for (i = 0; i < ARRAY_LEN (key->mask.as_u64); i++) { if (key->mask.as_u64[i] != r->mask.as_u64[i]) return 0; } return 1; } u8 RT (rule_is_match_for_key) (RTT (mma_mask_or_match) * key, RTT (mma_rule) * r) { RTT (mma_mask_or_match) _tmp_key, *tkp = &_tmp_key; int i; *tkp = *key; for (i = 0; i < ARRAY_LEN (tkp->as_u64); i++) tkp->as_u64[i] &= r->mask.as_u64[i]; for (i = 0; i < ARRAY_LEN (tkp->as_u64); i++) { if (tkp->as_u64[i] != r->match.as_u64[i]) return 0; } return 1; } RTT (mma_rule) * RT (mma_rules_table_rule_alloc) (RTT (mma_rules_table) * srt) { RTT (mma_rule) * rule; pool_get (srt->rules, rule); clib_memset (rule, 0, sizeof (*rule)); return rule; } RTT (mma_rule) * RT (mma_rule_free) (RTT (mma_rules_table) * srt, RTT (mma_rule) * rule) { clib_memset (rule, 0xfa, sizeof (*rule)); pool_put (srt->rules, rule); return rule; } RTT (mma_rule) * RT (mma_rules_table_get_rule) (RTT (mma_rules_table) * srt, u32 srt_index) { if (!pool_is_free_index (srt->rules, srt_index)) return (srt->rules + srt_index); return 0; } u32 RT (mma_rules_table_rule_index) (RTT (mma_rules_table) * srt, RTT (mma_rule) * sr) { ASSERT (sr); return (sr - srt->rules); } /** * Lookup key in table * * This should be optimized .. eventually */ u32 RT (mma_rules_table_lookup) (RTT (mma_rules_table) * srt, RTT (mma_mask_or_match) * key, u32 rule_index) { RTT (mma_rule) * rp; u32 rv; int i; ASSERT (rule_index != MMA_TABLE_INVALID_INDEX); rp = RT (mma_rules_table_get_rule) (srt, rule_index); ASSERT (rp); if (!RT (rule_is_match_for_key) (key, rp)) return MMA_TABLE_INVALID_INDEX; for (i = 0; i < vec_len (rp->next_indices); i++) { rv = RT (mma_rules_table_lookup) (srt, key, rp->next_indices[i]); if (rv != MMA_TABLE_INVALID_INDEX) return (rv); } return (rp->action_index); } u32 RT (mma_rules_table_lookup_rule) (RTT (mma_rules_table) * srt, RTT (mma_mask_or_match) * key, u32 rule_index) { RTT (mma_rule) * rp; u32 rv; int i; ASSERT (rule_index != MMA_TABLE_INVALID_INDEX); rp = RT (mma_rules_table_get_rule) (srt, rule_index); ASSERT (rp); if (!RT (rule_is_match_for_key) (key, rp)) return MMA_TABLE_INVALID_INDEX; for (i = 0; i < vec_len (rp->next_indices); i++) { rv = RT (mma_rules_table_lookup_rule) (srt, key, rp->next_indices[i]); if (rv != MMA_TABLE_INVALID_INDEX) return (rv); } return rule_index; } static RTT (mma_rules_table) * RTT (sort_srt); int RT (mma_sort_indices) (void *e1, void *e2) { u32 *ri1 = e1, *ri2 = e2; RTT (mma_rule) * rule1, *rule2; rule1 = RT (mma_rules_table_get_rule) (RTT (sort_srt), *ri1); rule2 = RT (mma_rules_table_get_rule) (RTT (sort_srt), *ri2); return RTT (sort_srt)->rule_cmp_fn (rule1, rule2); } void RT (mma_sort) (RTT (mma_rules_table) * srt, u32 * next_indices) { RTT (sort_srt) = srt; vec_sort_with_function (next_indices, RT (mma_sort_indices)); } int RT (mma_rules_table_add_rule) (RTT (mma_rules_table) * srt, RTT (mma_rule) * rule) { u32 parent_index, i, *next_indices = 0, added = 0, rule_index; RTT (mma_rule) * parent, *child; rule_index = RT (mma_rules_table_rule_index) (srt, rule); parent_index = RT (mma_rules_table_lookup_rule) (srt, &rule->match, srt->root_index); parent = RT (mma_rules_table_get_rule) (srt, parent_index); if (RT (rule_is_exact_match) (rule, parent)) { parent->action_index = rule->action_index; RT (mma_rule_free) (srt, rule); return -1; } if (vec_len (parent->next_indices) == 0) { vec_add1 (parent->next_indices, rule_index); return 0; } /* Check if new rule is parent of some of the existing children */ for (i = 0; i < vec_len (parent->next_indices); i++) { child = RT (mma_rules_table_get_rule) (srt, parent->next_indices[i]); if (RT (rule_is_match_for_key) (&child->match, rule)) { vec_add1 (rule->next_indices, parent->next_indices[i]); if (!added) { vec_add1 (next_indices, rule_index); added = 1; } } else { if (!added && srt->rule_cmp_fn (rule, child) < 0) { vec_add1 (next_indices, rule_index); added = 1; } vec_add1 (next_indices, parent->next_indices[i]); } } if (!added) vec_add1 (next_indices, rule_index); vec_free (parent->next_indices); parent->next_indices = next_indices; return 0; } int RT (mma_rules_table_del_rule) (RTT (mma_rules_table) * srt, RTT (mma_rule) * rule, u32 rule_index) { RTT (mma_rule) * rp; u32 rv; int i; ASSERT (rule_index != MMA_TABLE_INVALID_INDEX); rp = RT (mma_rules_table_get_rule) (srt, rule_index); if (!RT (rule_is_match_for_key) (&rule->match, rp)) return MMA_TABLE_INVALID_INDEX; if (RT (rule_is_exact_match) (rule, rp)) { if (rule_index == srt->root_index) rp->action_index = MMA_TABLE_INVALID_INDEX; return 1; } for (i = 0; i < vec_len (rp->next_indices); i++) { rv = RT (mma_rules_table_del_rule) (srt, rule, rp->next_indices[i]); if (rv == 1) { RTT (mma_rule) * child; u32 *next_indices = 0, *new_elts, left_to_add; child = RT (mma_rules_table_get_rule) (srt, rp->next_indices[i]); ASSERT (RT (rule_is_exact_match) (rule, child)); if (i != 0) { vec_add2 (next_indices, new_elts, i); clib_memcpy_fast (new_elts, rp->next_indices, i * sizeof (u32)); } if (vec_len (child->next_indices)) vec_append (next_indices, child->next_indices); left_to_add = vec_len (rp->next_indices) - i - 1; if (left_to_add) { vec_add2 (next_indices, new_elts, left_to_add); clib_memcpy_fast (new_elts, &rp->next_indices[i + 1], left_to_add * sizeof (u32)); } RT (mma_rule_free) (srt, child); vec_free (rp->next_indices); rp->next_indices = next_indices; return 0; } else if (rv == 0) return rv; } return MMA_TABLE_INVALID_INDEX; } /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */