/*
* 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:
*/