vlib: improvement to automatic core pinning
[vpp.git] / src / plugins / acl / hash_lookup.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stddef.h>
19 #include <netinet/in.h>
20
21 #include <vlibapi/api.h>
22 #include <vlibmemory/api.h>
23
24 #include <vlib/vlib.h>
25 #include <vnet/vnet.h>
26 #include <vppinfra/error.h>
27 #include <vnet/plugin/plugin.h>
28 #include <acl/acl.h>
29 #include <vppinfra/bihash_48_8.h>
30
31 #include "hash_lookup.h"
32 #include "hash_lookup_private.h"
33
34
35 always_inline applied_hash_ace_entry_t **get_applied_hash_aces(acl_main_t *am, u32 lc_index)
36 {
37   applied_hash_ace_entry_t **applied_hash_aces = vec_elt_at_index(am->hash_entry_vec_by_lc_index, lc_index);
38
39 /*is_input ? vec_elt_at_index(am->input_hash_entry_vec_by_sw_if_index, sw_if_index)
40                                                           : vec_elt_at_index(am->output_hash_entry_vec_by_sw_if_index, sw_if_index);
41 */
42   return applied_hash_aces;
43 }
44
45
46 static void
47 hashtable_add_del(acl_main_t *am, clib_bihash_kv_48_8_t *kv, int is_add)
48 {
49     DBG("HASH ADD/DEL: %016llx %016llx %016llx %016llx %016llx %016llx %016llx add %d",
50                         kv->key[0], kv->key[1], kv->key[2],
51                         kv->key[3], kv->key[4], kv->key[5], kv->value, is_add);
52     BV (clib_bihash_add_del) (&am->acl_lookup_hash, kv, is_add);
53 }
54
55 /*
56  * TupleMerge
57  *
58  * Initial adaptation by Valerio Bruschi (valerio.bruschi@telecom-paristech.fr)
59  * based on the TupleMerge [1] simulator kindly made available
60  * by  James Daly (dalyjamese@gmail.com) and  Eric Torng (torng@cse.msu.edu)
61  * ( http://www.cse.msu.edu/~dalyjame/ or http://www.cse.msu.edu/~torng/ ),
62  * refactoring by Andrew Yourtchenko.
63  *
64  * [1] James Daly, Eric Torng "TupleMerge: Building Online Packet Classifiers
65  * by Omitting Bits", In Proc. IEEE ICCCN 2017, pp. 1-10
66  *
67  */
68
69 static int
70 count_bits (u64 word)
71 {
72   int counter = 0;
73   while (word)
74     {
75       counter += word & 1;
76       word >>= 1;
77     }
78   return counter;
79 }
80
81 /* check if mask2 can be contained by mask1 */
82 static u8
83 first_mask_contains_second_mask(int is_ip6, fa_5tuple_t * mask1, fa_5tuple_t * mask2)
84 {
85   int i;
86   if (is_ip6)
87     {
88       for (i = 0; i < 2; i++)
89         {
90           if ((mask1->ip6_addr[0].as_u64[i] & mask2->ip6_addr[0].as_u64[i]) !=
91               mask1->ip6_addr[0].as_u64[i])
92             return 0;
93           if ((mask1->ip6_addr[1].as_u64[i] & mask2->ip6_addr[1].as_u64[i]) !=
94               mask1->ip6_addr[1].as_u64[i])
95             return 0;
96         }
97     }
98   else
99     {
100       /* check the pads, both masks must have it 0 */
101       u32 padcheck = 0;
102       int i;
103       for (i=0; i<6; i++) {
104         padcheck |= mask1->l3_zero_pad[i];
105         padcheck |= mask2->l3_zero_pad[i];
106       }
107       if (padcheck != 0)
108         return 0;
109       if ((mask1->ip4_addr[0].as_u32 & mask2->ip4_addr[0].as_u32) !=
110           mask1->ip4_addr[0].as_u32)
111         return 0;
112       if ((mask1->ip4_addr[1].as_u32 & mask2->ip4_addr[1].as_u32) !=
113           mask1->ip4_addr[1].as_u32)
114         return 0;
115     }
116
117   /* take care if port are not exact-match  */
118   if ((mask1->l4.as_u64 & mask2->l4.as_u64) != mask1->l4.as_u64)
119     return 0;
120
121   if ((mask1->pkt.as_u64 & mask2->pkt.as_u64) != mask1->pkt.as_u64)
122     return 0;
123
124   return 1;
125 }
126
127
128
129 /*
130  * TupleMerge:
131  *
132  * Consider the situation when we have to create a new table
133  * T for a given rule R. This occurs for the first rule inserted and
134  * for later rules if it is incompatible with all existing tables.
135  * In this event, we need to determine mT for a new table.
136  * Setting mT = mR is not a good strategy; if another similar,
137  * but slightly less specific, rule appears we will be unable to
138  * add it to T and will thus have to create another new table. We
139  * thus consider two factors: is the rule more strongly aligned
140  * with source or destination addresses (usually the two most
141  * important fields) and how much slack needs to be given to
142  * allow for other rules. If the source and destination addresses
143  * are close together (within 4 bits for our experiments), we use
144  * both of them. Otherwise, we drop the smaller (less specific)
145  * address and its associated port field from consideration; R is
146  * predominantly aligned with one of the two fields and should
147  * be grouped with other similar rules. This is similar to TSS
148  * dropping port fields, but since it is based on observable rule
149  * characteristics it is more likely to keep important fields and
150  * discard less useful ones.
151  * We then look at the absolute lengths of the addresses. If
152  * the address is long, we are more likely to try to add shorter
153  * lengths and likewise the reverse. We thus remove a few bits
154  * from both address fields with more bits removed from longer
155  * addresses. For 32 bit addresses, we remove 4 bits, 3 for more
156  * than 24, 2 for more than 16, and so on (so 8 and fewer bits
157  * don’t have any removed). We only do this for prefix fields like
158  * addresses; both range fields (like ports) and exact match fields
159  * (like protocol) should remain as they are.
160  */
161
162
163 static u32
164 shift_ip4_if(u32 mask, u32 thresh, int numshifts, u32 else_val)
165 {
166   if (mask > thresh)
167      return clib_host_to_net_u32((clib_net_to_host_u32(mask) << numshifts) & 0xFFFFFFFF);
168   else
169      return else_val;
170 }
171
172 static void
173 relax_ip4_addr(ip4_address_t *ip4_mask, int relax2) {
174   int shifts_per_relax[2][4] = { { 6, 5, 4, 2 }, { 3, 2, 1, 1 } };
175
176   int *shifts = shifts_per_relax[relax2];
177   if(ip4_mask->as_u32 == 0xffffffff)
178     ip4_mask->as_u32 = clib_host_to_net_u32((clib_net_to_host_u32(ip4_mask->as_u32) << shifts[0])&0xFFFFFFFF);
179   else
180     ip4_mask->as_u32 = shift_ip4_if(ip4_mask->as_u32, 0xffffff00, shifts[1],
181                         shift_ip4_if(ip4_mask->as_u32, 0xffff0000, shifts[2],
182                           shift_ip4_if(ip4_mask->as_u32, 0xff000000, shifts[3], ip4_mask->as_u32)));
183 }
184
185 static void
186 relax_ip6_addr(ip6_address_t *ip6_mask, int relax2) {
187   /*
188    * This "better than nothing" relax logic is based on heuristics
189    * from IPv6 knowledge, and may not be optimal.
190    * Some further tuning may be needed in the future.
191    */
192   if (ip6_mask->as_u64[0] == 0xffffffffffffffffULL) {
193     if (ip6_mask->as_u64[1] == 0xffffffffffffffffULL) {
194       /* relax a /128 down to /64  - likely to have more hosts */
195       ip6_mask->as_u64[1] = 0;
196     } else if (ip6_mask->as_u64[1] == 0) {
197       /* relax a /64 down to /56 - likely to have more subnets */
198       ip6_mask->as_u64[0] = clib_host_to_net_u64(0xffffffffffffff00ULL);
199     }
200   }
201 }
202
203 static void
204 relax_tuple(fa_5tuple_t *mask, int is_ip6, int relax2){
205         fa_5tuple_t save_mask = *mask;
206
207         int counter_s = 0, counter_d = 0;
208         if (is_ip6) {
209           int i;
210           for(i=0; i<2; i++){
211                 counter_s += count_bits(mask->ip6_addr[0].as_u64[i]);
212                 counter_d += count_bits(mask->ip6_addr[1].as_u64[i]);
213           }
214         } else {
215                 counter_s += count_bits(mask->ip4_addr[0].as_u32);
216                 counter_d += count_bits(mask->ip4_addr[1].as_u32);
217         }
218
219 /*
220  * is the rule more strongly aligned with source or destination addresses
221  * (usually the two most important fields) and how much slack needs to be
222  * given to allow for other rules. If the source and destination addresses
223  * are close together (within 4 bits for our experiments), we use both of them.
224  * Otherwise, we drop the smaller (less specific) address and its associated
225  * port field from consideration
226  */
227         const int deltaThreshold = 4;
228         /* const int deltaThreshold = 8; if IPV6? */
229         int delta = counter_s - counter_d;
230         if (-delta > deltaThreshold) {
231                 if (is_ip6)
232                   mask->ip6_addr[0].as_u64[1] = mask->ip6_addr[0].as_u64[0] = 0;
233                 else
234                   mask->ip4_addr[0].as_u32 = 0;
235                 mask->l4.port[0] = 0;
236         } else if (delta > deltaThreshold) {
237                 if (is_ip6)
238                   mask->ip6_addr[1].as_u64[1] = mask->ip6_addr[1].as_u64[0] = 0;
239                 else
240                   mask->ip4_addr[1].as_u32 = 0;
241                 mask->l4.port[1] = 0;
242         }
243
244         if (is_ip6) {
245           relax_ip6_addr(&mask->ip6_addr[0], relax2);
246           relax_ip6_addr(&mask->ip6_addr[1], relax2);
247         } else {
248           relax_ip4_addr(&mask->ip4_addr[0], relax2);
249           relax_ip4_addr(&mask->ip4_addr[1], relax2);
250         }
251         mask->pkt.is_nonfirst_fragment = 0;
252         mask->pkt.l4_valid = 0;
253         if(!first_mask_contains_second_mask(is_ip6, mask, &save_mask)){
254                 DBG( "TM-relaxing-ERROR");
255                 *mask = save_mask;
256         }
257         DBG( "TM-relaxing-end");
258 }
259
260 static u32
261 find_mask_type_index(acl_main_t *am, fa_5tuple_t *mask)
262 {
263   ace_mask_type_entry_t *mte;
264   pool_foreach (mte, am->ace_mask_type_pool)
265    {
266     if(memcmp(&mte->mask, mask, sizeof(*mask)) == 0)
267       return (mte - am->ace_mask_type_pool);
268   }
269   return ~0;
270 }
271
272 static u32
273 assign_mask_type_index(acl_main_t *am, fa_5tuple_t *mask)
274 {
275   u32 mask_type_index = find_mask_type_index(am, mask);
276   ace_mask_type_entry_t *mte;
277   if(~0 == mask_type_index) {
278     pool_get_aligned (am->ace_mask_type_pool, mte, CLIB_CACHE_LINE_BYTES);
279     mask_type_index = mte - am->ace_mask_type_pool;
280     clib_memcpy_fast(&mte->mask, mask, sizeof(mte->mask));
281     mte->refcount = 0;
282
283     /*
284      * We can use only 16 bits, since in the match there is only u16 field.
285      * Realistically, once you go to 64K of mask types, it is a huge
286      * problem anyway, so we might as well stop half way.
287      */
288     ASSERT(mask_type_index < 32768);
289   }
290   mte = am->ace_mask_type_pool + mask_type_index;
291   mte->refcount++;
292   DBG0("ASSIGN MTE index %d new refcount %d", mask_type_index, mte->refcount);
293   return mask_type_index;
294 }
295
296 static void
297 lock_mask_type_index(acl_main_t *am, u32 mask_type_index)
298 {
299   DBG0("LOCK MTE index %d", mask_type_index);
300   ace_mask_type_entry_t *mte = pool_elt_at_index(am->ace_mask_type_pool, mask_type_index);
301   mte->refcount++;
302   DBG0("LOCK MTE index %d new refcount %d", mask_type_index, mte->refcount);
303 }
304
305
306 static void
307 release_mask_type_index(acl_main_t *am, u32 mask_type_index)
308 {
309   DBG0("RELEAS MTE index %d", mask_type_index);
310   ace_mask_type_entry_t *mte = pool_elt_at_index(am->ace_mask_type_pool, mask_type_index);
311   mte->refcount--;
312   DBG0("RELEAS MTE index %d new refcount %d", mask_type_index, mte->refcount);
313   if (mte->refcount == 0) {
314     /* we are not using this entry anymore */
315     clib_memset(mte, 0xae, sizeof(*mte));
316     pool_put(am->ace_mask_type_pool, mte);
317   }
318 }
319
320
321 static u32
322 tm_assign_mask_type_index(acl_main_t *am, fa_5tuple_t *mask, int is_ip6, u32 lc_index)
323 {
324         u32 mask_type_index = ~0;
325         u32 for_mask_type_index = ~0;
326         ace_mask_type_entry_t *mte = 0;
327         int order_index;
328         /* look for existing mask comparable with the one in input */
329
330         hash_applied_mask_info_t **hash_applied_mask_info_vec = vec_elt_at_index(am->hash_applied_mask_info_vec_by_lc_index, lc_index);
331         hash_applied_mask_info_t *minfo;
332
333         if (vec_len(*hash_applied_mask_info_vec) > 0) {
334             for(order_index = vec_len((*hash_applied_mask_info_vec)) -1; order_index >= 0; order_index--) {
335                 minfo = vec_elt_at_index((*hash_applied_mask_info_vec), order_index);
336                 for_mask_type_index = minfo->mask_type_index;
337                 mte = vec_elt_at_index(am->ace_mask_type_pool, for_mask_type_index);
338                 if(first_mask_contains_second_mask(is_ip6, &mte->mask, mask)){
339                         mask_type_index = (mte - am->ace_mask_type_pool);
340                         lock_mask_type_index(am, mask_type_index);
341                         break;
342                 }
343             }
344         }
345
346         if(~0 == mask_type_index) {
347                 /* if no mask is found, then let's use a relaxed version of the original one, in order to be used by new ace_entries */
348                 DBG( "TM-assigning mask type index-new one");
349                 fa_5tuple_t relaxed_mask = *mask;
350                 relax_tuple(&relaxed_mask, is_ip6, 0);
351                 mask_type_index = assign_mask_type_index(am, &relaxed_mask);
352
353                 hash_applied_mask_info_t **hash_applied_mask_info_vec = vec_elt_at_index(am->hash_applied_mask_info_vec_by_lc_index, lc_index);
354
355                 int spot = vec_len((*hash_applied_mask_info_vec));
356                 vec_validate((*hash_applied_mask_info_vec), spot);
357                 minfo = vec_elt_at_index((*hash_applied_mask_info_vec), spot);
358                 minfo->mask_type_index = mask_type_index;
359                 minfo->num_entries = 0;
360                 minfo->max_collisions = 0;
361                 minfo->first_rule_index = ~0;
362
363                 /*
364                  * We can use only 16 bits, since in the match there is only u16 field.
365                  * Realistically, once you go to 64K of mask types, it is a huge
366                  * problem anyway, so we might as well stop half way.
367                  */
368                 ASSERT(mask_type_index < 32768);
369         }
370         mte = am->ace_mask_type_pool + mask_type_index;
371         DBG0("TM-ASSIGN MTE index %d new refcount %d", mask_type_index, mte->refcount);
372         return mask_type_index;
373 }
374
375
376 static void
377 fill_applied_hash_ace_kv(acl_main_t *am,
378                             applied_hash_ace_entry_t **applied_hash_aces,
379                             u32 lc_index,
380                             u32 new_index, clib_bihash_kv_48_8_t *kv)
381 {
382   fa_5tuple_t *kv_key = (fa_5tuple_t *)kv->key;
383   hash_acl_lookup_value_t *kv_val = (hash_acl_lookup_value_t *)&kv->value;
384   applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), new_index);
385   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, pae->acl_index);
386
387   /* apply the mask to ace key */
388   hash_ace_info_t *ace_info = vec_elt_at_index(ha->rules, pae->hash_ace_info_index);
389   ace_mask_type_entry_t *mte = vec_elt_at_index(am->ace_mask_type_pool, pae->mask_type_index);
390
391   u64 *pmatch = (u64 *) &ace_info->match;
392   u64 *pmask = (u64 *)&mte->mask;
393   u64 *pkey = (u64 *)kv->key;
394
395   *pkey++ = *pmatch++ & *pmask++;
396   *pkey++ = *pmatch++ & *pmask++;
397   *pkey++ = *pmatch++ & *pmask++;
398   *pkey++ = *pmatch++ & *pmask++;
399   *pkey++ = *pmatch++ & *pmask++;
400   *pkey++ = *pmatch++ & *pmask++;
401
402   kv_key->pkt.mask_type_index_lsb = pae->mask_type_index;
403   kv_key->pkt.lc_index = lc_index;
404   kv_val->as_u64 = 0;
405   kv_val->applied_entry_index = new_index;
406 }
407
408 static void
409 add_del_hashtable_entry(acl_main_t *am,
410                             u32 lc_index,
411                             applied_hash_ace_entry_t **applied_hash_aces,
412                             u32 index, int is_add)
413 {
414   clib_bihash_kv_48_8_t kv;
415
416   fill_applied_hash_ace_kv(am, applied_hash_aces, lc_index, index, &kv);
417   hashtable_add_del(am, &kv, is_add);
418 }
419
420
421 static void
422 remake_hash_applied_mask_info_vec (acl_main_t * am,
423                                    applied_hash_ace_entry_t **
424                                    applied_hash_aces, u32 lc_index)
425 {
426   DBG0("remake applied hash mask info lc_index %d", lc_index);
427   hash_applied_mask_info_t *new_hash_applied_mask_info_vec =
428     vec_new (hash_applied_mask_info_t, 0);
429
430   hash_applied_mask_info_t *minfo;
431   int i;
432   for (i = 0; i < vec_len ((*applied_hash_aces)); i++)
433     {
434       applied_hash_ace_entry_t *pae =
435         vec_elt_at_index ((*applied_hash_aces), i);
436
437       /* check if mask_type_index is already there */
438       u32 new_pointer = vec_len (new_hash_applied_mask_info_vec);
439       int search;
440       for (search = 0; search < vec_len (new_hash_applied_mask_info_vec);
441            search++)
442         {
443           minfo = vec_elt_at_index (new_hash_applied_mask_info_vec, search);
444           if (minfo->mask_type_index == pae->mask_type_index)
445             break;
446         }
447
448       vec_validate ((new_hash_applied_mask_info_vec), search);
449       minfo = vec_elt_at_index ((new_hash_applied_mask_info_vec), search);
450       if (search == new_pointer)
451         {
452           DBG0("remaking index %d", search);
453           minfo->mask_type_index = pae->mask_type_index;
454           minfo->num_entries = 0;
455           minfo->max_collisions = 0;
456           minfo->first_rule_index = ~0;
457         }
458
459       minfo->num_entries = minfo->num_entries + 1;
460
461       if (vec_len (pae->colliding_rules) > minfo->max_collisions)
462         minfo->max_collisions = vec_len (pae->colliding_rules);
463
464       if (minfo->first_rule_index > i)
465         minfo->first_rule_index = i;
466     }
467
468   hash_applied_mask_info_t **hash_applied_mask_info_vec =
469     vec_elt_at_index (am->hash_applied_mask_info_vec_by_lc_index, lc_index);
470
471   vec_free ((*hash_applied_mask_info_vec));
472   (*hash_applied_mask_info_vec) = new_hash_applied_mask_info_vec;
473 }
474
475 static void
476 vec_del_collision_rule (collision_match_rule_t ** pvec,
477                         u32 applied_entry_index)
478 {
479   u32 i = 0;
480   u32 deleted = 0;
481   while (i < _vec_len ((*pvec)))
482     {
483       collision_match_rule_t *cr = vec_elt_at_index ((*pvec), i);
484       if (cr->applied_entry_index == applied_entry_index)
485         {
486           /* vec_del1 ((*pvec), i) would be more efficient but would reorder the elements. */
487           vec_delete((*pvec), 1, i);
488           deleted++;
489           DBG0("vec_del_collision_rule deleting one at index %d", i);
490         }
491       else
492         {
493           i++;
494         }
495     }
496   ASSERT(deleted > 0);
497 }
498
499 static void
500 acl_plugin_print_pae (vlib_main_t * vm, int j, applied_hash_ace_entry_t * pae);
501
502 static void
503 del_colliding_rule (applied_hash_ace_entry_t ** applied_hash_aces,
504                     u32 head_index, u32 applied_entry_index)
505 {
506   DBG0("DEL COLLIDING RULE: head_index %d applied index %d", head_index, applied_entry_index);
507
508
509   applied_hash_ace_entry_t *head_pae =
510     vec_elt_at_index ((*applied_hash_aces), head_index);
511   if (ACL_HASH_LOOKUP_DEBUG > 0)
512     acl_plugin_print_pae(acl_main.vlib_main, head_index, head_pae);
513   vec_del_collision_rule (&head_pae->colliding_rules, applied_entry_index);
514   if (vec_len(head_pae->colliding_rules) == 0) {
515     vec_free(head_pae->colliding_rules);
516   }
517   if (ACL_HASH_LOOKUP_DEBUG > 0)
518     acl_plugin_print_pae(acl_main.vlib_main, head_index, head_pae);
519 }
520
521 static void
522 add_colliding_rule (acl_main_t * am,
523                     applied_hash_ace_entry_t ** applied_hash_aces,
524                     u32 head_index, u32 applied_entry_index)
525 {
526   applied_hash_ace_entry_t *head_pae =
527     vec_elt_at_index ((*applied_hash_aces), head_index);
528   applied_hash_ace_entry_t *pae =
529     vec_elt_at_index ((*applied_hash_aces), applied_entry_index);
530   DBG0("ADD COLLIDING RULE: head_index %d applied index %d", head_index, applied_entry_index);
531   if (ACL_HASH_LOOKUP_DEBUG > 0)
532     acl_plugin_print_pae(acl_main.vlib_main, head_index, head_pae);
533
534   collision_match_rule_t cr;
535
536   cr.acl_index = pae->acl_index;
537   cr.ace_index = pae->ace_index;
538   cr.acl_position = pae->acl_position;
539   cr.applied_entry_index = applied_entry_index;
540   cr.rule = am->acls[pae->acl_index].rules[pae->ace_index];
541   pae->collision_head_ae_index = head_index;
542   vec_add1 (head_pae->colliding_rules, cr);
543   if (ACL_HASH_LOOKUP_DEBUG > 0)
544     acl_plugin_print_pae(acl_main.vlib_main, head_index, head_pae);
545 }
546
547 static u32
548 activate_applied_ace_hash_entry(acl_main_t *am,
549                             u32 lc_index,
550                             applied_hash_ace_entry_t **applied_hash_aces,
551                             u32 new_index)
552 {
553   clib_bihash_kv_48_8_t kv;
554   ASSERT(new_index != ~0);
555   DBG("activate_applied_ace_hash_entry lc_index %d new_index %d", lc_index, new_index);
556
557   fill_applied_hash_ace_kv(am, applied_hash_aces, lc_index, new_index, &kv);
558
559   DBG("APPLY ADD KY: %016llx %016llx %016llx %016llx %016llx %016llx",
560                         kv.key[0], kv.key[1], kv.key[2],
561                         kv.key[3], kv.key[4], kv.key[5]);
562
563   clib_bihash_kv_48_8_t result;
564   hash_acl_lookup_value_t *result_val = (hash_acl_lookup_value_t *)&result.value;
565   int res = BV (clib_bihash_search) (&am->acl_lookup_hash, &kv, &result);
566   ASSERT(new_index != ~0);
567   ASSERT(new_index < vec_len((*applied_hash_aces)));
568   if (res == 0) {
569     u32 first_index = result_val->applied_entry_index;
570     ASSERT(first_index != ~0);
571     ASSERT(first_index < vec_len((*applied_hash_aces)));
572     /* There already exists an entry or more. Append at the end. */
573     DBG("A key already exists, with applied entry index: %d", first_index);
574     add_colliding_rule(am, applied_hash_aces, first_index, new_index);
575     return first_index;
576   } else {
577     /* It's the very first entry */
578     hashtable_add_del(am, &kv, 1);
579     ASSERT(new_index != ~0);
580     add_colliding_rule(am, applied_hash_aces, new_index, new_index);
581     return new_index;
582   }
583 }
584
585
586 static void
587 assign_mask_type_index_to_pae(acl_main_t *am, u32 lc_index, int is_ip6, applied_hash_ace_entry_t *pae)
588 {
589   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, pae->acl_index);
590   hash_ace_info_t *ace_info = vec_elt_at_index(ha->rules, pae->hash_ace_info_index);
591
592   ace_mask_type_entry_t *mte;
593   fa_5tuple_t mask;
594   /*
595    * Start taking base_mask associated to ace, and essentially copy it.
596    * With TupleMerge we will assign a relaxed mask here.
597    */
598   mte = vec_elt_at_index(am->ace_mask_type_pool, ace_info->base_mask_type_index);
599   mask = mte->mask;
600   if (am->use_tuple_merge)
601     pae->mask_type_index = tm_assign_mask_type_index(am, &mask, is_ip6, lc_index);
602   else
603     pae->mask_type_index = assign_mask_type_index(am, &mask);
604 }
605
606 static void
607 split_partition(acl_main_t *am, u32 first_index,
608                             u32 lc_index, int is_ip6);
609
610
611 static void
612 check_collision_count_and_maybe_split(acl_main_t *am, u32 lc_index, int is_ip6, u32 first_index)
613 {
614   applied_hash_ace_entry_t **applied_hash_aces = get_applied_hash_aces(am, lc_index);
615   applied_hash_ace_entry_t *first_pae = vec_elt_at_index((*applied_hash_aces), first_index);
616   if (vec_len(first_pae->colliding_rules) > am->tuple_merge_split_threshold) {
617     split_partition(am, first_index, lc_index, is_ip6);
618   }
619 }
620
621 void
622 hash_acl_apply(acl_main_t *am, u32 lc_index, int acl_index, u32 acl_position)
623 {
624   int i;
625
626   DBG0("HASH ACL apply: lc_index %d acl %d", lc_index, acl_index);
627   if (!am->acl_lookup_hash_initialized) {
628     BV (clib_bihash_init) (&am->acl_lookup_hash, "ACL plugin rule lookup bihash",
629                            am->hash_lookup_hash_buckets, am->hash_lookup_hash_memory);
630     am->acl_lookup_hash_initialized = 1;
631   }
632
633   vec_validate(am->hash_entry_vec_by_lc_index, lc_index);
634   vec_validate(am->hash_acl_infos, acl_index);
635   applied_hash_ace_entry_t **applied_hash_aces = get_applied_hash_aces(am, lc_index);
636
637   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, acl_index);
638   u32 **hash_acl_applied_lc_index = &ha->lc_index_list;
639
640   int base_offset = vec_len(*applied_hash_aces);
641
642   /* Update the bitmap of the mask types with which the lookup
643      needs to happen for the ACLs applied to this lc_index */
644   applied_hash_acl_info_t **applied_hash_acls = &am->applied_hash_acl_info_by_lc_index;
645   vec_validate((*applied_hash_acls), lc_index);
646   applied_hash_acl_info_t *pal = vec_elt_at_index((*applied_hash_acls), lc_index);
647
648   /* ensure the list of applied hash acls is initialized and add this acl# to it */
649   u32 index = vec_search(pal->applied_acls, acl_index);
650   if (index != ~0) {
651     clib_warning("BUG: trying to apply twice acl_index %d on lc_index %d, according to lc",
652                  acl_index, lc_index);
653     ASSERT(0);
654     return;
655   }
656   vec_add1(pal->applied_acls, acl_index);
657   u32 index2 = vec_search((*hash_acl_applied_lc_index), lc_index);
658   if (index2 != ~0) {
659     clib_warning("BUG: trying to apply twice acl_index %d on lc_index %d, according to hash h-acl info",
660                  acl_index, lc_index);
661     ASSERT(0);
662     return;
663   }
664   vec_add1((*hash_acl_applied_lc_index), lc_index);
665
666   /*
667    * if the applied ACL is empty, the current code will cause a
668    * different behavior compared to current linear search: an empty ACL will
669    * simply fallthrough to the next ACL, or the default deny in the end.
670    *
671    * This is not a problem, because after vpp-dev discussion,
672    * the consensus was it should not be possible to apply the non-existent
673    * ACL, so the change adding this code also takes care of that.
674    */
675
676
677   vec_validate(am->hash_applied_mask_info_vec_by_lc_index, lc_index);
678
679   /* since we know (in case of no split) how much we expand, preallocate that space */
680   if (vec_len(ha->rules) > 0) {
681     int old_vec_len = vec_len(*applied_hash_aces);
682     vec_validate((*applied_hash_aces), old_vec_len + vec_len(ha->rules) - 1);
683     vec_set_len ((*applied_hash_aces), old_vec_len);
684   }
685
686   /* add the rules from the ACL to the hash table for lookup and append to the vector*/
687   for(i=0; i < vec_len(ha->rules); i++) {
688     /*
689      * Expand the applied aces vector to fit a new entry.
690      * One by one not to upset split_partition() if it is called.
691      */
692     vec_resize((*applied_hash_aces), 1);
693
694     int is_ip6 = ha->rules[i].match.pkt.is_ip6;
695     u32 new_index = base_offset + i;
696     applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), new_index);
697     pae->acl_index = acl_index;
698     pae->ace_index = ha->rules[i].ace_index;
699     pae->acl_position = acl_position;
700     pae->action = ha->rules[i].action;
701     pae->hitcount = 0;
702     pae->hash_ace_info_index = i;
703     /* we might link it in later */
704     pae->collision_head_ae_index = ~0;
705     pae->colliding_rules = NULL;
706     pae->mask_type_index = ~0;
707     assign_mask_type_index_to_pae(am, lc_index, is_ip6, pae);
708     u32 first_index = activate_applied_ace_hash_entry(am, lc_index, applied_hash_aces, new_index);
709     if (am->use_tuple_merge)
710       check_collision_count_and_maybe_split(am, lc_index, is_ip6, first_index);
711   }
712   remake_hash_applied_mask_info_vec(am, applied_hash_aces, lc_index);
713 }
714
715 static u32
716 find_head_applied_ace_index(applied_hash_ace_entry_t **applied_hash_aces, u32 curr_index)
717 {
718   ASSERT(curr_index != ~0);
719   applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), curr_index);
720   ASSERT(pae);
721   ASSERT(pae->collision_head_ae_index != ~0);
722   return pae->collision_head_ae_index;
723 }
724
725 static void
726 set_collision_head_ae_index(applied_hash_ace_entry_t **applied_hash_aces, collision_match_rule_t *colliding_rules, u32 new_index)
727 {
728         collision_match_rule_t *cr;
729         vec_foreach(cr, colliding_rules) {
730             applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), cr->applied_entry_index);
731             pae->collision_head_ae_index = new_index;
732         }
733 }
734
735 static void
736 move_applied_ace_hash_entry(acl_main_t *am,
737                             u32 lc_index,
738                             applied_hash_ace_entry_t **applied_hash_aces,
739                             u32 old_index, u32 new_index)
740 {
741   ASSERT(old_index != ~0);
742   ASSERT(new_index != ~0);
743   /* move the entry */
744   *vec_elt_at_index((*applied_hash_aces), new_index) = *vec_elt_at_index((*applied_hash_aces), old_index);
745
746   /* update the linkage and hash table if necessary */
747   applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), old_index);
748   applied_hash_ace_entry_t *new_pae = vec_elt_at_index((*applied_hash_aces), new_index);
749
750   if (ACL_HASH_LOOKUP_DEBUG > 0) {
751     clib_warning("Moving pae from %d to %d", old_index, new_index);
752     acl_plugin_print_pae(am->vlib_main, old_index, pae);
753   }
754
755   if (pae->collision_head_ae_index == old_index) {
756     /* first entry - so the hash points to it, update */
757     add_del_hashtable_entry(am, lc_index,
758                             applied_hash_aces, new_index, 1);
759   }
760   if (new_pae->colliding_rules) {
761     /* update the information within the collision rule entry */
762     ASSERT(vec_len(new_pae->colliding_rules) > 0);
763     collision_match_rule_t *cr = vec_elt_at_index (new_pae->colliding_rules, 0);
764     ASSERT(cr->applied_entry_index == old_index);
765     cr->applied_entry_index = new_index;
766     set_collision_head_ae_index(applied_hash_aces, new_pae->colliding_rules, new_index);
767   } else {
768     /* find the index in the collision rule entry on the head element */
769     u32 head_index = find_head_applied_ace_index(applied_hash_aces, new_index);
770     ASSERT(head_index != ~0);
771     applied_hash_ace_entry_t *head_pae = vec_elt_at_index((*applied_hash_aces), head_index);
772     ASSERT(vec_len(head_pae->colliding_rules) > 0);
773     u32 i;
774     for (i=0; i<vec_len(head_pae->colliding_rules); i++) {
775       collision_match_rule_t *cr = vec_elt_at_index (head_pae->colliding_rules, i);
776       if (cr->applied_entry_index == old_index) {
777         cr->applied_entry_index = new_index;
778       }
779     }
780     if (ACL_HASH_LOOKUP_DEBUG > 0) {
781       clib_warning("Head pae at index %d after adjustment", head_index);
782       acl_plugin_print_pae(am->vlib_main, head_index, head_pae);
783     }
784   }
785   /* invalidate the old entry */
786   pae->collision_head_ae_index = ~0;
787   pae->colliding_rules = NULL;
788 }
789
790 static void
791 deactivate_applied_ace_hash_entry(acl_main_t *am,
792                             u32 lc_index,
793                             applied_hash_ace_entry_t **applied_hash_aces,
794                             u32 old_index)
795 {
796   applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), old_index);
797   DBG("UNAPPLY DEACTIVATE: lc_index %d applied index %d", lc_index, old_index);
798   if (ACL_HASH_LOOKUP_DEBUG > 0) {
799     clib_warning("Deactivating pae at index %d", old_index);
800     acl_plugin_print_pae(am->vlib_main, old_index, pae);
801   }
802
803   if (pae->collision_head_ae_index != old_index) {
804     DBG("UNAPPLY = index %d has collision head %d", old_index, pae->collision_head_ae_index);
805
806     u32 head_index = find_head_applied_ace_index(applied_hash_aces, old_index);
807     ASSERT(head_index != ~0);
808     del_colliding_rule(applied_hash_aces, head_index, old_index);
809
810   } else {
811     /* It was the first entry. We need either to reset the hash entry or delete it */
812     /* delete our entry from the collision vector first */
813     del_colliding_rule(applied_hash_aces, old_index, old_index);
814     if (vec_len(pae->colliding_rules) > 0) {
815       u32 next_pae_index = pae->colliding_rules[0].applied_entry_index;
816       applied_hash_ace_entry_t *next_pae = vec_elt_at_index((*applied_hash_aces), next_pae_index);
817       /* Remove ourselves and transfer the ownership of the colliding rules vector */
818       next_pae->colliding_rules = pae->colliding_rules;
819       set_collision_head_ae_index(applied_hash_aces, next_pae->colliding_rules, next_pae_index);
820       add_del_hashtable_entry(am, lc_index,
821                               applied_hash_aces, next_pae_index, 1);
822     } else {
823       /* no next entry, so just delete the entry in the hash table */
824       add_del_hashtable_entry(am, lc_index,
825                               applied_hash_aces, old_index, 0);
826     }
827   }
828   DBG0("Releasing mask type index %d for pae index %d on lc_index %d", pae->mask_type_index, old_index, lc_index);
829   release_mask_type_index(am, pae->mask_type_index);
830   /* invalidate the old entry */
831   pae->mask_type_index = ~0;
832   pae->collision_head_ae_index = ~0;
833   /* always has to be 0 */
834   pae->colliding_rules = NULL;
835 }
836
837
838 void
839 hash_acl_unapply(acl_main_t *am, u32 lc_index, int acl_index)
840 {
841   int i;
842
843   DBG0("HASH ACL unapply: lc_index %d acl %d", lc_index, acl_index);
844   applied_hash_acl_info_t **applied_hash_acls = &am->applied_hash_acl_info_by_lc_index;
845   applied_hash_acl_info_t *pal = vec_elt_at_index((*applied_hash_acls), lc_index);
846
847   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, acl_index);
848   u32 **hash_acl_applied_lc_index = &ha->lc_index_list;
849
850   if (ACL_HASH_LOOKUP_DEBUG > 0) {
851     clib_warning("unapplying acl %d", acl_index);
852     acl_plugin_show_tables_mask_type();
853     acl_plugin_show_tables_acl_hash_info(acl_index);
854     acl_plugin_show_tables_applied_info(lc_index);
855   }
856
857   /* remove this acl# from the list of applied hash acls */
858   u32 index = vec_search(pal->applied_acls, acl_index);
859   if (index == ~0) {
860     clib_warning("BUG: trying to unapply unapplied acl_index %d on lc_index %d, according to lc",
861                  acl_index, lc_index);
862     return;
863   }
864   vec_del1(pal->applied_acls, index);
865
866   u32 index2 = vec_search((*hash_acl_applied_lc_index), lc_index);
867   if (index2 == ~0) {
868     clib_warning("BUG: trying to unapply twice acl_index %d on lc_index %d, according to h-acl info",
869                  acl_index, lc_index);
870     return;
871   }
872   vec_del1((*hash_acl_applied_lc_index), index2);
873
874   applied_hash_ace_entry_t **applied_hash_aces = get_applied_hash_aces(am, lc_index);
875
876   for(i=0; i < vec_len((*applied_hash_aces)); i++) {
877     if (vec_elt_at_index(*applied_hash_aces,i)->acl_index == acl_index) {
878       DBG("Found applied ACL#%d at applied index %d", acl_index, i);
879       break;
880     }
881   }
882   if (vec_len((*applied_hash_aces)) <= i) {
883     DBG("Did not find applied ACL#%d at lc_index %d", acl_index, lc_index);
884     /* we went all the way without finding any entries. Probably a list was empty. */
885     return;
886   }
887
888   int base_offset = i;
889   int tail_offset = base_offset + vec_len(ha->rules);
890   int tail_len = vec_len((*applied_hash_aces)) - tail_offset;
891   DBG("base_offset: %d, tail_offset: %d, tail_len: %d", base_offset, tail_offset, tail_len);
892
893   for(i=0; i < vec_len(ha->rules); i ++) {
894     deactivate_applied_ace_hash_entry(am, lc_index,
895                                       applied_hash_aces, base_offset + i);
896   }
897   for(i=0; i < tail_len; i ++) {
898     /* move the entry at tail offset to base offset */
899     /* that is, from (tail_offset+i) -> (base_offset+i) */
900     DBG0("UNAPPLY MOVE: lc_index %d, applied index %d -> %d", lc_index, tail_offset+i, base_offset + i);
901     move_applied_ace_hash_entry(am, lc_index, applied_hash_aces, tail_offset + i, base_offset + i);
902   }
903   /* trim the end of the vector */
904   vec_dec_len ((*applied_hash_aces), vec_len (ha->rules));
905
906   remake_hash_applied_mask_info_vec(am, applied_hash_aces, lc_index);
907
908   if (vec_len((*applied_hash_aces)) == 0) {
909     vec_free((*applied_hash_aces));
910   }
911 }
912
913 /*
914  * Create the applied ACEs and update the hash table,
915  * taking into account that the ACL may not be the last
916  * in the vector of applied ACLs.
917  *
918  * For now, walk from the end of the vector and unapply the ACLs,
919  * then apply the one in question and reapply the rest.
920  */
921
922 void
923 hash_acl_reapply(acl_main_t *am, u32 lc_index, int acl_index)
924 {
925   acl_lookup_context_t *acontext = pool_elt_at_index(am->acl_lookup_contexts, lc_index);
926   u32 **applied_acls = &acontext->acl_indices;
927   int i;
928   int start_index = vec_search((*applied_acls), acl_index);
929
930   DBG0("Start index for acl %d in lc_index %d is %d", acl_index, lc_index, start_index);
931   /*
932    * This function is called after we find out the lc_index where ACL is applied.
933    * If the by-lc_index vector does not have the ACL#, then it's a bug.
934    */
935   ASSERT(start_index < vec_len(*applied_acls));
936
937   /* unapply all the ACLs at the tail side, up to the current one */
938   for(i = vec_len(*applied_acls) - 1; i > start_index; i--) {
939     hash_acl_unapply(am, lc_index, *vec_elt_at_index(*applied_acls, i));
940   }
941   for(i = start_index; i < vec_len(*applied_acls); i++) {
942     hash_acl_apply(am, lc_index, *vec_elt_at_index(*applied_acls, i), i);
943   }
944 }
945
946 static void
947 make_ip6_address_mask(ip6_address_t *addr, u8 prefix_len)
948 {
949   ip6_address_mask_from_width(addr, prefix_len);
950 }
951
952
953 /* Maybe should be moved into the core somewhere */
954 always_inline void
955 ip4_address_mask_from_width (ip4_address_t * a, u32 width)
956 {
957   int i, byte, bit, bitnum;
958   ASSERT (width <= 32);
959   clib_memset (a, 0, sizeof (a[0]));
960   for (i = 0; i < width; i++)
961     {
962       bitnum = (7 - (i & 7));
963       byte = i / 8;
964       bit = 1 << bitnum;
965       a->as_u8[byte] |= bit;
966     }
967 }
968
969
970 static void
971 make_ip4_address_mask(ip4_address_t *addr, u8 prefix_len)
972 {
973   ip4_address_mask_from_width(addr, prefix_len);
974 }
975
976 static void
977 make_port_mask(u16 *portmask, u16 port_first, u16 port_last)
978 {
979   if (port_first == port_last) {
980     *portmask = 0xffff;
981     /* single port is representable by masked value */
982     return;
983   }
984
985   *portmask = 0;
986   return;
987 }
988
989 static void
990 make_mask_and_match_from_rule(fa_5tuple_t *mask, acl_rule_t *r, hash_ace_info_t *hi)
991 {
992   clib_memset(mask, 0, sizeof(*mask));
993   clib_memset(&hi->match, 0, sizeof(hi->match));
994   hi->action = r->is_permit;
995
996   /* we will need to be matching based on lc_index and mask_type_index when applied */
997   mask->pkt.lc_index = ~0;
998   /* we will assign the match of mask_type_index later when we find it*/
999   mask->pkt.mask_type_index_lsb = ~0;
1000
1001   mask->pkt.is_ip6 = 1;
1002   hi->match.pkt.is_ip6 = r->is_ipv6;
1003   if (r->is_ipv6) {
1004     make_ip6_address_mask(&mask->ip6_addr[0], r->src_prefixlen);
1005     hi->match.ip6_addr[0] = r->src.ip6;
1006     make_ip6_address_mask(&mask->ip6_addr[1], r->dst_prefixlen);
1007     hi->match.ip6_addr[1] = r->dst.ip6;
1008   } else {
1009     clib_memset(hi->match.l3_zero_pad, 0, sizeof(hi->match.l3_zero_pad));
1010     make_ip4_address_mask(&mask->ip4_addr[0], r->src_prefixlen);
1011     hi->match.ip4_addr[0] = r->src.ip4;
1012     make_ip4_address_mask(&mask->ip4_addr[1], r->dst_prefixlen);
1013     hi->match.ip4_addr[1] = r->dst.ip4;
1014   }
1015
1016   if (r->proto != 0) {
1017     mask->l4.proto = ~0; /* L4 proto needs to be matched */
1018     hi->match.l4.proto = r->proto;
1019
1020     /* Calculate the src/dst port masks and make the src/dst port matches accordingly */
1021     make_port_mask(&mask->l4.port[0], r->src_port_or_type_first, r->src_port_or_type_last);
1022     hi->match.l4.port[0] = r->src_port_or_type_first & mask->l4.port[0];
1023
1024     make_port_mask(&mask->l4.port[1], r->dst_port_or_code_first, r->dst_port_or_code_last);
1025     hi->match.l4.port[1] = r->dst_port_or_code_first & mask->l4.port[1];
1026     /* L4 info must be valid in order to match */
1027     mask->pkt.l4_valid = 1;
1028     hi->match.pkt.l4_valid = 1;
1029     /* And we must set the mask to check that it is an initial fragment */
1030     mask->pkt.is_nonfirst_fragment = 1;
1031     hi->match.pkt.is_nonfirst_fragment = 0;
1032     if ((r->proto == IPPROTO_TCP) && (r->tcp_flags_mask != 0)) {
1033       /* if we want to match on TCP flags, they must be masked off as well */
1034       mask->pkt.tcp_flags = r->tcp_flags_mask;
1035       hi->match.pkt.tcp_flags = r->tcp_flags_value;
1036       /* and the flags need to be present within the packet being matched */
1037       mask->pkt.tcp_flags_valid = 1;
1038       hi->match.pkt.tcp_flags_valid = 1;
1039     }
1040   }
1041   /* Sanitize the mask and the match */
1042   u64 *pmask = (u64 *)mask;
1043   u64 *pmatch = (u64 *)&hi->match;
1044   int j;
1045   for(j=0; j<6; j++) {
1046     pmatch[j] = pmatch[j] & pmask[j];
1047   }
1048 }
1049
1050
1051 int hash_acl_exists(acl_main_t *am, int acl_index)
1052 {
1053   if (acl_index >= vec_len(am->hash_acl_infos))
1054     return 0;
1055
1056   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, acl_index);
1057   return ha->hash_acl_exists;
1058 }
1059
1060 void hash_acl_add(acl_main_t *am, int acl_index)
1061 {
1062   DBG("HASH ACL add : %d", acl_index);
1063   int i;
1064   acl_rule_t *acl_rules = am->acls[acl_index].rules;
1065   vec_validate(am->hash_acl_infos, acl_index);
1066   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, acl_index);
1067   clib_memset(ha, 0, sizeof(*ha));
1068   ha->hash_acl_exists = 1;
1069
1070   /* walk the newly added ACL entries and ensure that for each of them there
1071      is a mask type, increment a reference count for that mask type */
1072
1073   /* avoid small requests by preallocating the entire vector before running the additions */
1074   if (vec_len(acl_rules) > 0) {
1075     vec_validate(ha->rules, vec_len(acl_rules)-1);
1076     vec_reset_length(ha->rules);
1077   }
1078
1079   for(i=0; i < vec_len(acl_rules); i++) {
1080     hash_ace_info_t ace_info;
1081     fa_5tuple_t mask;
1082     clib_memset(&ace_info, 0, sizeof(ace_info));
1083     ace_info.acl_index = acl_index;
1084     ace_info.ace_index = i;
1085
1086     make_mask_and_match_from_rule(&mask, &acl_rules[i], &ace_info);
1087     mask.pkt.flags_reserved = 0b000;
1088     ace_info.base_mask_type_index = assign_mask_type_index(am, &mask);
1089     /* assign the mask type index for matching itself */
1090     ace_info.match.pkt.mask_type_index_lsb = ace_info.base_mask_type_index;
1091     DBG("ACE: %d mask_type_index: %d", i, ace_info.base_mask_type_index);
1092     vec_add1(ha->rules, ace_info);
1093   }
1094   /*
1095    * if an ACL is applied somewhere, fill the corresponding lookup data structures.
1096    * We need to take care if the ACL is not the last one in the vector of ACLs applied to the interface.
1097    */
1098   if (acl_index < vec_len(am->lc_index_vec_by_acl)) {
1099     u32 *lc_index;
1100     vec_foreach(lc_index, am->lc_index_vec_by_acl[acl_index]) {
1101       hash_acl_reapply(am, *lc_index, acl_index);
1102     }
1103   }
1104 }
1105
1106 void hash_acl_delete(acl_main_t *am, int acl_index)
1107 {
1108   DBG0("HASH ACL delete : %d", acl_index);
1109   /*
1110    * If the ACL is applied somewhere, remove the references of it (call hash_acl_unapply)
1111    * this is a different behavior from the linear lookup where an empty ACL is "deny all",
1112    *
1113    * However, following vpp-dev discussion the ACL that is referenced elsewhere
1114    * should not be possible to delete, and the change adding this also adds
1115    * the safeguards to that respect, so this is not a problem.
1116    *
1117    * The part to remember is that this routine is called in process of reapplication
1118    * during the acl_add_replace() API call - the old acl ruleset is deleted, then
1119    * the new one is added, without the change in the applied ACLs - so this case
1120    * has to be handled.
1121    */
1122   hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, acl_index);
1123   u32 *lc_list_copy = 0;
1124   {
1125     u32 *lc_index;
1126     lc_list_copy = vec_dup(ha->lc_index_list);
1127     vec_foreach(lc_index, lc_list_copy) {
1128       hash_acl_unapply(am, *lc_index, acl_index);
1129     }
1130     vec_free(lc_list_copy);
1131   }
1132   vec_free(ha->lc_index_list);
1133
1134   /* walk the mask types for the ACL about-to-be-deleted, and decrease
1135    * the reference count, possibly freeing up some of them */
1136   int i;
1137   for(i=0; i < vec_len(ha->rules); i++) {
1138     release_mask_type_index(am, ha->rules[i].base_mask_type_index);
1139   }
1140   ha->hash_acl_exists = 0;
1141   vec_free(ha->rules);
1142 }
1143
1144
1145 void
1146 show_hash_acl_hash (vlib_main_t * vm, acl_main_t *am, u32 verbose)
1147 {
1148   vlib_cli_output(vm, "\nACL lookup hash table:\n%U\n",
1149                   BV (format_bihash), &am->acl_lookup_hash, verbose);
1150 }
1151
1152 void
1153 acl_plugin_show_tables_mask_type (void)
1154 {
1155   acl_main_t *am = &acl_main;
1156   vlib_main_t *vm = am->vlib_main;
1157   ace_mask_type_entry_t *mte;
1158
1159   vlib_cli_output (vm, "Mask-type entries:");
1160     pool_foreach (mte, am->ace_mask_type_pool)
1161      {
1162       vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
1163                     mte - am->ace_mask_type_pool,
1164                     mte->mask.kv_40_8.key[0], mte->mask.kv_40_8.key[1], mte->mask.kv_40_8.key[2],
1165                     mte->mask.kv_40_8.key[3], mte->mask.kv_40_8.key[4], mte->mask.kv_40_8.value, mte->refcount);
1166     }
1167 }
1168
1169 void
1170 acl_plugin_show_tables_acl_hash_info (u32 acl_index)
1171 {
1172   acl_main_t *am = &acl_main;
1173   vlib_main_t *vm = am->vlib_main;
1174   u32 i, j;
1175   u64 *m;
1176   vlib_cli_output (vm, "Mask-ready ACL representations\n");
1177   for (i = 0; i < vec_len (am->hash_acl_infos); i++)
1178     {
1179       if ((acl_index != ~0) && (acl_index != i))
1180         {
1181           continue;
1182         }
1183       hash_acl_info_t *ha = &am->hash_acl_infos[i];
1184       vlib_cli_output (vm, "acl-index %u bitmask-ready layout\n", i);
1185       vlib_cli_output (vm, "  applied lc_index list: %U\n",
1186                        format_vec32, ha->lc_index_list, "%d");
1187       for (j = 0; j < vec_len (ha->rules); j++)
1188         {
1189           hash_ace_info_t *pa = &ha->rules[j];
1190           m = (u64 *) & pa->match;
1191           vlib_cli_output (vm,
1192                            "    %4d: %016llx %016llx %016llx %016llx %016llx %016llx base mask index %d acl %d rule %d action %d\n",
1193                            j, m[0], m[1], m[2], m[3], m[4], m[5],
1194                            pa->base_mask_type_index, pa->acl_index, pa->ace_index,
1195                            pa->action);
1196         }
1197     }
1198 }
1199
1200 static void
1201 acl_plugin_print_colliding_rule (vlib_main_t * vm, int j, collision_match_rule_t *cr) {
1202   vlib_cli_output(vm,
1203                   "        %4d: acl %d ace %d acl pos %d pae index: %d",
1204                   j, cr->acl_index, cr->ace_index, cr->acl_position, cr->applied_entry_index);
1205 }
1206
1207 static void
1208 acl_plugin_print_pae (vlib_main_t * vm, int j, applied_hash_ace_entry_t * pae)
1209 {
1210   vlib_cli_output (vm,
1211                    "    %4d: acl %d rule %d action %d bitmask-ready rule %d mask type index: %d colliding_rules: %d collision_head_ae_idx %d hitcount %lld acl_pos: %d",
1212                    j, pae->acl_index, pae->ace_index, pae->action,
1213                    pae->hash_ace_info_index, pae->mask_type_index, vec_len(pae->colliding_rules), pae->collision_head_ae_index,
1214                    pae->hitcount, pae->acl_position);
1215   int jj;
1216   for(jj=0; jj<vec_len(pae->colliding_rules); jj++)
1217     acl_plugin_print_colliding_rule(vm, jj, vec_elt_at_index(pae->colliding_rules, jj));
1218 }
1219
1220 static void
1221 acl_plugin_print_applied_mask_info (vlib_main_t * vm, int j, hash_applied_mask_info_t *mi)
1222 {
1223   vlib_cli_output (vm,
1224                    "    %4d: mask type index %d first rule index %d num_entries %d max_collisions %d",
1225                    j, mi->mask_type_index, mi->first_rule_index, mi->num_entries, mi->max_collisions);
1226 }
1227
1228 void
1229 acl_plugin_show_tables_applied_info (u32 lc_index)
1230 {
1231   acl_main_t *am = &acl_main;
1232   vlib_main_t *vm = am->vlib_main;
1233   u32 lci, j;
1234   vlib_cli_output (vm, "Applied lookup entries for lookup contexts");
1235
1236   for (lci = 0;
1237        (lci < vec_len(am->applied_hash_acl_info_by_lc_index)); lci++)
1238     {
1239       if ((lc_index != ~0) && (lc_index != lci))
1240         {
1241           continue;
1242         }
1243       vlib_cli_output (vm, "lc_index %d:", lci);
1244       if (lci < vec_len (am->applied_hash_acl_info_by_lc_index))
1245         {
1246           applied_hash_acl_info_t *pal =
1247             &am->applied_hash_acl_info_by_lc_index[lci];
1248           vlib_cli_output (vm, "  applied acls: %U", format_vec32,
1249                            pal->applied_acls, "%d");
1250         }
1251       if (lci < vec_len (am->hash_applied_mask_info_vec_by_lc_index))
1252         {
1253           vlib_cli_output (vm, "  applied mask info entries:");
1254           for (j = 0;
1255                j < vec_len (am->hash_applied_mask_info_vec_by_lc_index[lci]);
1256                j++)
1257             {
1258               acl_plugin_print_applied_mask_info (vm, j,
1259                                     &am->hash_applied_mask_info_vec_by_lc_index
1260                                     [lci][j]);
1261             }
1262         }
1263       if (lci < vec_len (am->hash_entry_vec_by_lc_index))
1264         {
1265           vlib_cli_output (vm, "  lookup applied entries:");
1266           for (j = 0;
1267                j < vec_len (am->hash_entry_vec_by_lc_index[lci]);
1268                j++)
1269             {
1270               acl_plugin_print_pae (vm, j,
1271                                     &am->hash_entry_vec_by_lc_index
1272                                     [lci][j]);
1273             }
1274         }
1275     }
1276 }
1277
1278 void
1279 acl_plugin_show_tables_bihash (u32 show_bihash_verbose)
1280 {
1281   acl_main_t *am = &acl_main;
1282   vlib_main_t *vm = am->vlib_main;
1283   show_hash_acl_hash (vm, am, show_bihash_verbose);
1284 }
1285
1286 /*
1287  * Split of the partition needs to happen when the collision count
1288  * goes over a specified threshold.
1289  *
1290  * This is a signal that we ignored too many bits in
1291  * mT and we need to split the table into two tables. We select
1292  * all of the colliding rules L and find their maximum common
1293  * tuple mL. Normally mL is specific enough to hash L with few
1294  * or no collisions. We then create a new table T2 with tuple mL
1295  * and transfer all compatible rules from T to T2. If mL is not
1296  * specific enough, we find the field with the biggest difference
1297  * between the minimum and maximum tuple lengths for all of
1298  * the rules in L and set that field to be the average of those two
1299  * values. We then transfer all compatible rules as before. This
1300  * guarantees that some rules from L will move and that T2 will
1301  * have a smaller number of collisions than T did.
1302  */
1303
1304
1305 static void
1306 ensure_ip6_min_addr (ip6_address_t * min_addr, ip6_address_t * mask_addr)
1307 {
1308   int update =
1309     (clib_net_to_host_u64 (mask_addr->as_u64[0]) <
1310      clib_net_to_host_u64 (min_addr->as_u64[0]))
1311     ||
1312     ((clib_net_to_host_u64 (mask_addr->as_u64[0]) ==
1313       clib_net_to_host_u64 (min_addr->as_u64[0]))
1314      && (clib_net_to_host_u64 (mask_addr->as_u64[1]) <
1315          clib_net_to_host_u64 (min_addr->as_u64[1])));
1316   if (update)
1317     {
1318       min_addr->as_u64[0] = mask_addr->as_u64[0];
1319       min_addr->as_u64[1] = mask_addr->as_u64[1];
1320     }
1321 }
1322
1323 static void
1324 ensure_ip6_max_addr (ip6_address_t * max_addr, ip6_address_t * mask_addr)
1325 {
1326   int update =
1327     (clib_net_to_host_u64 (mask_addr->as_u64[0]) >
1328      clib_net_to_host_u64 (max_addr->as_u64[0]))
1329     ||
1330     ((clib_net_to_host_u64 (mask_addr->as_u64[0]) ==
1331       clib_net_to_host_u64 (max_addr->as_u64[0]))
1332      && (clib_net_to_host_u64 (mask_addr->as_u64[1]) >
1333          clib_net_to_host_u64 (max_addr->as_u64[1])));
1334   if (update)
1335     {
1336       max_addr->as_u64[0] = mask_addr->as_u64[0];
1337       max_addr->as_u64[1] = mask_addr->as_u64[1];
1338     }
1339 }
1340
1341 static void
1342 ensure_ip4_min_addr (ip4_address_t * min_addr, ip4_address_t * mask_addr)
1343 {
1344   int update =
1345     (clib_net_to_host_u32 (mask_addr->as_u32) <
1346      clib_net_to_host_u32 (min_addr->as_u32));
1347   if (update)
1348     min_addr->as_u32 = mask_addr->as_u32;
1349 }
1350
1351 static void
1352 ensure_ip4_max_addr (ip4_address_t * max_addr, ip4_address_t * mask_addr)
1353 {
1354   int update =
1355     (clib_net_to_host_u32 (mask_addr->as_u32) >
1356      clib_net_to_host_u32 (max_addr->as_u32));
1357   if (update)
1358     max_addr->as_u32 = mask_addr->as_u32;
1359 }
1360
1361 enum {
1362   DIM_SRC_ADDR = 0,
1363   DIM_DST_ADDR,
1364   DIM_SRC_PORT,
1365   DIM_DST_PORT,
1366   DIM_PROTO,
1367 };
1368
1369
1370
1371 static void
1372 split_partition(acl_main_t *am, u32 first_index,
1373                             u32 lc_index, int is_ip6){
1374         DBG( "TM-split_partition - first_entry:%d", first_index);
1375         applied_hash_ace_entry_t **applied_hash_aces = get_applied_hash_aces(am, lc_index);
1376         ace_mask_type_entry_t *mte;
1377         fa_5tuple_t the_min_tuple, *min_tuple = &the_min_tuple;
1378         fa_5tuple_t the_max_tuple, *max_tuple = &the_max_tuple;
1379         applied_hash_ace_entry_t *pae = vec_elt_at_index((*applied_hash_aces), first_index);
1380         hash_acl_info_t *ha = vec_elt_at_index(am->hash_acl_infos, pae->acl_index);
1381         hash_ace_info_t *ace_info;
1382         u32 coll_mask_type_index = pae->mask_type_index;
1383         clib_memset(&the_min_tuple, 0, sizeof(the_min_tuple));
1384         clib_memset(&the_max_tuple, 0, sizeof(the_max_tuple));
1385
1386         int i=0;
1387         collision_match_rule_t *colliding_rules = pae->colliding_rules;
1388         u64 collisions = vec_len(pae->colliding_rules);
1389         for(i=0; i<collisions; i++){
1390                 /* reload the hash acl info as it might be a different ACL# */
1391                 pae = vec_elt_at_index((*applied_hash_aces), colliding_rules[i].applied_entry_index);
1392                 ha = vec_elt_at_index(am->hash_acl_infos, pae->acl_index);
1393
1394                 DBG( "TM-collision: base_ace:%d (ace_mask:%d, first_collision_mask:%d)",
1395                                 pae->ace_index, pae->mask_type_index, coll_mask_type_index);
1396
1397                 ace_info = vec_elt_at_index(ha->rules, pae->hash_ace_info_index);
1398                 mte = vec_elt_at_index(am->ace_mask_type_pool, ace_info->base_mask_type_index);
1399                 fa_5tuple_t *mask = &mte->mask;
1400
1401                 if(pae->mask_type_index != coll_mask_type_index) continue;
1402                 /* Computing min_mask and max_mask for colliding rules */
1403                 if(i==0){
1404                         clib_memcpy_fast(min_tuple, mask, sizeof(fa_5tuple_t));
1405                         clib_memcpy_fast(max_tuple, mask, sizeof(fa_5tuple_t));
1406                 }else{
1407                         int j;
1408                         for(j=0; j<2; j++){
1409                                 if (is_ip6)
1410                                   ensure_ip6_min_addr(&min_tuple->ip6_addr[j], &mask->ip6_addr[j]);
1411                                 else
1412                                   ensure_ip4_min_addr(&min_tuple->ip4_addr[j], &mask->ip4_addr[j]);
1413
1414                                 if ((mask->l4.port[j] < min_tuple->l4.port[j]))
1415                                         min_tuple->l4.port[j] = mask->l4.port[j];
1416                         }
1417
1418                         if ((mask->l4.proto < min_tuple->l4.proto))
1419                                 min_tuple->l4.proto = mask->l4.proto;
1420
1421                         if(mask->pkt.as_u64 < min_tuple->pkt.as_u64)
1422                                 min_tuple->pkt.as_u64 = mask->pkt.as_u64;
1423
1424
1425                         for(j=0; j<2; j++){
1426                                 if (is_ip6)
1427                                   ensure_ip6_max_addr(&max_tuple->ip6_addr[j], &mask->ip6_addr[j]);
1428                                 else
1429                                   ensure_ip4_max_addr(&max_tuple->ip4_addr[j], &mask->ip4_addr[j]);
1430
1431                                 if ((mask->l4.port[j] > max_tuple->l4.port[j]))
1432                                         max_tuple->l4.port[j] = mask->l4.port[j];
1433                         }
1434
1435                         if ((mask->l4.proto < max_tuple->l4.proto))
1436                                 max_tuple->l4.proto = mask->l4.proto;
1437
1438                         if(mask->pkt.as_u64 > max_tuple->pkt.as_u64)
1439                                 max_tuple->pkt.as_u64 = mask->pkt.as_u64;
1440                 }
1441         }
1442
1443         /* Computing field with max difference between (min/max)_mask */
1444         int best_dim=-1, best_delta=0, delta=0;
1445
1446         /* SRC_addr dimension */
1447         if (is_ip6) {
1448           int i;
1449           for(i=0; i<2; i++){
1450                 delta += count_bits(max_tuple->ip6_addr[0].as_u64[i]) - count_bits(min_tuple->ip6_addr[0].as_u64[i]);
1451           }
1452         } else {
1453                 delta += count_bits(max_tuple->ip4_addr[0].as_u32) - count_bits(min_tuple->ip4_addr[0].as_u32);
1454         }
1455         if(delta > best_delta){
1456                 best_delta = delta;
1457                 best_dim = DIM_SRC_ADDR;
1458         }
1459
1460         /* DST_addr dimension */
1461         delta = 0;
1462         if (is_ip6) {
1463           int i;
1464           for(i=0; i<2; i++){
1465                 delta += count_bits(max_tuple->ip6_addr[1].as_u64[i]) - count_bits(min_tuple->ip6_addr[1].as_u64[i]);
1466           }
1467         } else {
1468                 delta += count_bits(max_tuple->ip4_addr[1].as_u32) - count_bits(min_tuple->ip4_addr[1].as_u32);
1469         }
1470         if(delta > best_delta){
1471                 best_delta = delta;
1472                 best_dim = DIM_DST_ADDR;
1473         }
1474
1475         /* SRC_port dimension */
1476         delta = count_bits(max_tuple->l4.port[0]) - count_bits(min_tuple->l4.port[0]);
1477         if(delta > best_delta){
1478                 best_delta = delta;
1479                 best_dim = DIM_SRC_PORT;
1480         }
1481
1482         /* DST_port dimension */
1483         delta = count_bits(max_tuple->l4.port[1]) - count_bits(min_tuple->l4.port[1]);
1484         if(delta > best_delta){
1485                 best_delta = delta;
1486                 best_dim = DIM_DST_PORT;
1487         }
1488
1489         /* Proto dimension */
1490         delta = count_bits(max_tuple->l4.proto) - count_bits(min_tuple->l4.proto);
1491         if(delta > best_delta){
1492                 best_delta = delta;
1493                 best_dim = DIM_PROTO;
1494         }
1495
1496         int shifting = 0; //, ipv4_block = 0;
1497         switch(best_dim){
1498                 case DIM_SRC_ADDR:
1499                         shifting = (best_delta)/2; // FIXME IPV4-only
1500                         // ipv4_block = count_bits(max_tuple->ip4_addr[0].as_u32);
1501                         min_tuple->ip4_addr[0].as_u32 =
1502                                         clib_host_to_net_u32((clib_net_to_host_u32(max_tuple->ip4_addr[0].as_u32) << (shifting))&0xFFFFFFFF);
1503
1504                         break;
1505                 case DIM_DST_ADDR:
1506                         shifting = (best_delta)/2;
1507 /*
1508                         ipv4_block = count_bits(max_tuple->addr[1].as_u64[1]);
1509                         if(ipv4_block > shifting)
1510                                 min_tuple->addr[1].as_u64[1] =
1511                                         clib_host_to_net_u64((clib_net_to_host_u64(max_tuple->addr[1].as_u64[1]) << (shifting))&0xFFFFFFFF);
1512                         else{
1513                                 shifting = shifting - ipv4_block;
1514                                 min_tuple->addr[1].as_u64[1] = 0;
1515                                 min_tuple->addr[1].as_u64[0] =
1516                                         clib_host_to_net_u64((clib_net_to_host_u64(max_tuple->addr[1].as_u64[0]) << (shifting))&0xFFFFFFFF);
1517                         }
1518 */
1519                         min_tuple->ip4_addr[1].as_u32 =
1520                                         clib_host_to_net_u32((clib_net_to_host_u32(max_tuple->ip4_addr[1].as_u32) << (shifting))&0xFFFFFFFF);
1521
1522                         break;
1523                 case DIM_SRC_PORT: min_tuple->l4.port[0] = max_tuple->l4.port[0]  << (best_delta)/2;
1524                         break;
1525                 case DIM_DST_PORT: min_tuple->l4.port[1] = max_tuple->l4.port[1] << (best_delta)/2;
1526                         break;
1527                 case DIM_PROTO: min_tuple->l4.proto = max_tuple->l4.proto << (best_delta)/2;
1528                         break;
1529                 default: relax_tuple(min_tuple, is_ip6, 1);
1530                         break;
1531         }
1532
1533         min_tuple->pkt.is_nonfirst_fragment = 0;
1534         u32 new_mask_type_index = assign_mask_type_index(am, min_tuple);
1535
1536         hash_applied_mask_info_t **hash_applied_mask_info_vec = vec_elt_at_index(am->hash_applied_mask_info_vec_by_lc_index, lc_index);
1537
1538         hash_applied_mask_info_t *minfo;
1539         //search in order pool if mask_type_index is already there
1540         int search;
1541         for (search=0; search < vec_len((*hash_applied_mask_info_vec)); search++){
1542                 minfo = vec_elt_at_index((*hash_applied_mask_info_vec), search);
1543                 if(minfo->mask_type_index == new_mask_type_index)
1544                         break;
1545         }
1546
1547         vec_validate((*hash_applied_mask_info_vec), search);
1548         minfo = vec_elt_at_index((*hash_applied_mask_info_vec), search);
1549         minfo->mask_type_index = new_mask_type_index;
1550         minfo->num_entries = 0;
1551         minfo->max_collisions = 0;
1552         minfo->first_rule_index = ~0;
1553
1554         DBG( "TM-split_partition - mask type index-assigned!! -> %d", new_mask_type_index);
1555
1556         if(coll_mask_type_index == new_mask_type_index){
1557                 //vlib_cli_output(vm, "TM-There are collisions over threshold, but i'm not able to split! %d %d", coll_mask_type_index, new_mask_type_index);
1558                 return;
1559         }
1560
1561
1562         /* populate new partition */
1563         DBG( "TM-Populate new partition");
1564         u32 r_ace_index = first_index;
1565         int repopulate_count = 0;
1566
1567         collision_match_rule_t *temp_colliding_rules = vec_dup(colliding_rules);
1568         collisions = vec_len(temp_colliding_rules);
1569
1570         for(i=0; i<collisions; i++){
1571
1572                 r_ace_index = temp_colliding_rules[i].applied_entry_index;
1573
1574                 applied_hash_ace_entry_t *pop_pae = vec_elt_at_index((*applied_hash_aces), r_ace_index);
1575                 ha = vec_elt_at_index(am->hash_acl_infos, pop_pae->acl_index);
1576                 DBG( "TM-Population-collision: base_ace:%d (ace_mask:%d, first_collision_mask:%d)",
1577                                 pop_pae->ace_index, pop_pae->mask_type_index, coll_mask_type_index);
1578
1579                 ASSERT(pop_pae->mask_type_index == coll_mask_type_index);
1580
1581                 ace_info = vec_elt_at_index(ha->rules, pop_pae->hash_ace_info_index);
1582                 mte = vec_elt_at_index(am->ace_mask_type_pool, ace_info->base_mask_type_index);
1583                 //can insert rule?
1584                 //mte = vec_elt_at_index(am->ace_mask_type_pool, pop_pae->mask_type_index);
1585                 fa_5tuple_t *pop_mask = &mte->mask;
1586
1587                 if(!first_mask_contains_second_mask(is_ip6, min_tuple, pop_mask)) continue;
1588                 DBG( "TM-new partition can insert -> applied_ace:%d", r_ace_index);
1589
1590                 //delete and insert in new format
1591                 deactivate_applied_ace_hash_entry(am, lc_index, applied_hash_aces, r_ace_index);
1592
1593                 /* insert the new entry */
1594                 pop_pae->mask_type_index = new_mask_type_index;
1595                 /* The very first repopulation gets the lock by virtue of a new mask being created above */
1596                 if (++repopulate_count > 1)
1597                   lock_mask_type_index(am, new_mask_type_index);
1598
1599                 activate_applied_ace_hash_entry(am, lc_index, applied_hash_aces, r_ace_index);
1600
1601         }
1602         vec_free(temp_colliding_rules);
1603
1604         DBG( "TM-Populate new partition-END");
1605         DBG( "TM-split_partition - END");
1606
1607 }