session: rules tables
[vpp.git] / src / vnet / session / mma_template.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15
16 #include <vppinfra/error.h>
17
18 u8 RT (rule_is_exact_match) (RTT (mma_rule) * key, RTT (mma_rule) * r)
19 {
20   int i;
21
22   for (i = 0; i < ARRAY_LEN (key->match.as_u64); i++)
23     {
24       if (key->match.as_u64[i] != r->match.as_u64[i])
25         return 0;
26     }
27   for (i = 0; i < ARRAY_LEN (key->mask.as_u64); i++)
28     {
29       if (key->mask.as_u64[i] != r->mask.as_u64[i])
30         return 0;
31     }
32   return 1;
33 }
34
35 u8
36 RT (rule_is_match_for_key) (RTT (mma_mask_or_match) * key, RTT (mma_rule) * r)
37 {
38   RTT (mma_mask_or_match) _tmp_key, *tkp = &_tmp_key;
39   int i;
40
41   *tkp = *key;
42   for (i = 0; i < ARRAY_LEN (tkp->as_u64); i++)
43     tkp->as_u64[i] &= r->mask.as_u64[i];
44   for (i = 0; i < ARRAY_LEN (tkp->as_u64); i++)
45     {
46       if (tkp->as_u64[i] != r->match.as_u64[i])
47         return 0;
48     }
49   return 1;
50 }
51
52 RTT (mma_rule) * RT (mma_rules_table_rule_alloc) (RTT (mma_rules_table) * srt)
53 {
54   RTT (mma_rule) * rule;
55   pool_get (srt->rules, rule);
56   memset (rule, 0, sizeof (*rule));
57   return rule;
58 }
59
60 RTT (mma_rule) *
61 RT (mma_rule_free) (RTT (mma_rules_table) * srt, RTT (mma_rule) * rule)
62 {
63   pool_put (srt->rules, rule);
64   memset (rule, 0xfa, sizeof (*rule));
65   return rule;
66 }
67
68 RTT (mma_rule) *
69 RT (mma_rules_table_get_rule) (RTT (mma_rules_table) * srt, u32 srt_index)
70 {
71   if (!pool_is_free_index (srt->rules, srt_index))
72     return (srt->rules + srt_index);
73   return 0;
74 }
75
76 u32
77 RT (mma_rules_table_rule_index) (RTT (mma_rules_table) * srt,
78                                  RTT (mma_rule) * sr)
79 {
80   ASSERT (sr);
81   return (sr - srt->rules);
82 }
83
84 /**
85  * Lookup key in table
86  *
87  * This should be optimized .. eventually
88  */
89 u32
90 RT (mma_rules_table_lookup) (RTT (mma_rules_table) * srt,
91                              RTT (mma_mask_or_match) * key, u32 rule_index)
92 {
93   RTT (mma_rule) * rp;
94   u32 rv;
95   int i;
96
97   ASSERT (rule_index != SESSION_RULES_TABLE_INVALID_INDEX);
98   rp = RT (mma_rules_table_get_rule) (srt, rule_index);
99   ASSERT (rp);
100
101   if (!RT (rule_is_match_for_key) (key, rp))
102     return ~0;
103   for (i = 0; i < vec_len (rp->next_indices); i++)
104     {
105       rv = RT (mma_rules_table_lookup) (srt, key, rp->next_indices[i]);
106       if (rv != ~0)
107         return (rv);
108     }
109   return (rp->action_index);
110 }
111
112 u32
113 RT (mma_rules_table_lookup_rule) (RTT (mma_rules_table) * srt,
114                                   RTT (mma_mask_or_match) * key,
115                                   u32 rule_index)
116 {
117   RTT (mma_rule) * rp;
118   u32 rv;
119   int i;
120
121   ASSERT (rule_index != SESSION_RULES_TABLE_INVALID_INDEX);
122   rp = RT (mma_rules_table_get_rule) (srt, rule_index);
123   ASSERT (rp);
124
125   if (!RT (rule_is_match_for_key) (key, rp))
126     return ~0;
127   for (i = 0; i < vec_len (rp->next_indices); i++)
128     {
129       rv = RT (mma_rules_table_lookup_rule) (srt, key, rp->next_indices[i]);
130       if (rv != ~0)
131         return (rv);
132     }
133   return rule_index;
134 }
135
136 static
137 RTT (mma_rules_table) *
138 RTT (sort_srt);
139
140      int RT (mma_sort_indices) (void *e1, void *e2)
141 {
142   u32 *ri1 = e1, *ri2 = e2;
143   RTT (mma_rule) * rule1, *rule2;
144   rule1 = RT (mma_rules_table_get_rule) (RTT (sort_srt), *ri1);
145   rule2 = RT (mma_rules_table_get_rule) (RTT (sort_srt), *ri2);
146   return RTT (sort_srt)->rule_cmp_fn (rule1, rule2);
147 }
148
149 void RT (mma_sort) (RTT (mma_rules_table) * srt, u32 * next_indices)
150 {
151   RTT (sort_srt) = srt;
152   vec_sort_with_function (next_indices, RT (mma_sort_indices));
153 }
154
155 int
156 RT (mma_rules_table_add_rule) (RTT (mma_rules_table) * srt,
157                                RTT (mma_rule) * rule)
158 {
159   u32 parent_index, i, *next_indices = 0, added = 0, rule_index;
160   RTT (mma_rule) * parent, *child;
161
162   rule_index = RT (mma_rules_table_rule_index) (srt, rule);
163   parent_index = RT (mma_rules_table_lookup_rule) (srt, &rule->match,
164                                                    srt->root_index);
165   parent = RT (mma_rules_table_get_rule) (srt, parent_index);
166   if (RT (rule_is_exact_match) (rule, parent))
167     {
168       parent->action_index = rule->action_index;
169       RT (mma_rule_free) (srt, rule);
170       return -1;
171     }
172
173   if (vec_len (parent->next_indices) == 0)
174     {
175       vec_add1 (parent->next_indices, rule_index);
176       return 0;
177     }
178
179   /* Check if new rule is parent of some of the existing children */
180   for (i = 0; i < vec_len (parent->next_indices); i++)
181     {
182       child = RT (mma_rules_table_get_rule) (srt, parent->next_indices[i]);
183       if (RT (rule_is_match_for_key) (&child->match, rule))
184         {
185           vec_add1 (rule->next_indices, parent->next_indices[i]);
186           if (!added)
187             {
188               vec_add1 (next_indices, rule_index);
189               added = 1;
190             }
191         }
192       else
193         {
194           if (!added && srt->rule_cmp_fn (rule, child) < 0)
195             {
196               vec_add1 (next_indices, rule_index);
197               added = 1;
198             }
199           vec_add1 (next_indices, parent->next_indices[i]);
200         }
201     }
202   if (!added)
203     vec_add1 (next_indices, rule_index);
204   vec_free (parent->next_indices);
205   parent->next_indices = next_indices;
206   return 0;
207 }
208
209 int
210 RT (mma_rules_table_del_rule) (RTT (mma_rules_table) * srt,
211                                RTT (mma_rule) * rule, u32 rule_index)
212 {
213   RTT (mma_rule) * rp;
214   u32 rv;
215   int i;
216
217   ASSERT (rule_index != SESSION_RULES_TABLE_INVALID_INDEX);
218   rp = RT (mma_rules_table_get_rule) (srt, rule_index);
219
220   if (!RT (rule_is_match_for_key) (&rule->match, rp))
221     return ~0;
222   if (RT (rule_is_exact_match) (rule, rp))
223     return 1;
224   for (i = 0; i < vec_len (rp->next_indices); i++)
225     {
226       rv = RT (mma_rules_table_del_rule) (srt, rule, rp->next_indices[i]);
227       if (rv == 1)
228         {
229           RTT (mma_rule) * child;
230           u32 *next_indices = 0, *new_elts, left_to_add;
231           child = RT (mma_rules_table_get_rule) (srt, rp->next_indices[i]);
232           ASSERT (RT (rule_is_exact_match) (rule, child));
233
234           if (i != 0)
235             {
236               vec_add2 (next_indices, new_elts, i);
237               clib_memcpy (new_elts, rp->next_indices, i * sizeof (u32));
238             }
239           if (vec_len (child->next_indices))
240             vec_append (next_indices, child->next_indices);
241           left_to_add = vec_len (rp->next_indices) - i - 1;
242           if (left_to_add)
243             {
244               vec_add2 (next_indices, new_elts, left_to_add);
245               clib_memcpy (new_elts, &rp->next_indices[i + 1],
246                            left_to_add * sizeof (u32));
247             }
248           RT (mma_rule_free) (srt, child);
249           vec_free (rp->next_indices);
250           rp->next_indices = next_indices;
251           return 0;
252         }
253       else if (rv == 0)
254         return rv;
255     }
256   return ~0;
257 }
258
259 /*
260  * fd.io coding-style-patch-verification: ON
261  *
262  * Local Variables:
263  * eval: (c-set-style "gnu")
264  * End:
265  */