acl-plugin: reject the too-short variable-length messages from clients (VPP-839)
[vpp.git] / src / plugins / acl / acl.c
1 /*
2  * Copyright (c) 2016 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 <stddef.h>
17
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <acl/acl.h>
21
22 #include <vnet/l2/l2_classify.h>
23 #include <vnet/classify/input_acl.h>
24 #include <vpp/app/version.h>
25
26 #include <vlibapi/api.h>
27 #include <vlibmemory/api.h>
28 #include <vlibsocket/api.h>
29
30 /* define message IDs */
31 #include <acl/acl_msg_enum.h>
32
33 /* define message structures */
34 #define vl_typedefs
35 #include <acl/acl_all_api_h.h>
36 #undef vl_typedefs
37
38 /* define generated endian-swappers */
39 #define vl_endianfun
40 #include <acl/acl_all_api_h.h>
41 #undef vl_endianfun
42
43 /* instantiate all the print functions we know about */
44 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #define vl_printfun
46 #include <acl/acl_all_api_h.h>
47 #undef vl_printfun
48
49 /* Get the API version number */
50 #define vl_api_version(n,v) static u32 api_version=(v);
51 #include <acl/acl_all_api_h.h>
52 #undef vl_api_version
53
54 #include "fa_node.h"
55
56 acl_main_t acl_main;
57
58 #define REPLY_MSG_ID_BASE am->msg_id_base
59 #include <vlibapi/api_helper_macros.h>
60
61 /* List of message types that this plugin understands */
62
63 #define foreach_acl_plugin_api_msg              \
64 _(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \
65 _(ACL_ADD_REPLACE, acl_add_replace)                             \
66 _(ACL_DEL, acl_del)                             \
67 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
68 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)       \
69 _(ACL_DUMP, acl_dump)  \
70 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
71 _(MACIP_ACL_ADD, macip_acl_add) \
72 _(MACIP_ACL_DEL, macip_acl_del) \
73 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
74 _(MACIP_ACL_DUMP, macip_acl_dump) \
75 _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get)
76
77 /* *INDENT-OFF* */
78 VLIB_PLUGIN_REGISTER () = {
79     .version = VPP_BUILD_VER,
80     .description = "Access Control Lists",
81 };
82 /* *INDENT-ON* */
83
84 static void
85 vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
86 {
87   acl_main_t *am = &acl_main;
88   vl_api_acl_plugin_get_version_reply_t *rmp;
89   int msg_size = sizeof (*rmp);
90   unix_shared_memory_queue_t *q;
91
92   q = vl_api_client_index_to_input_queue (mp->client_index);
93   if (q == 0)
94     {
95       return;
96     }
97
98   rmp = vl_msg_api_alloc (msg_size);
99   memset (rmp, 0, msg_size);
100   rmp->_vl_msg_id =
101     ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
102   rmp->context = mp->context;
103   rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
104   rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
105
106   vl_msg_api_send_shmem (q, (u8 *) & rmp);
107 }
108
109
110 static int
111 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
112               u32 * acl_list_index, u8 * tag)
113 {
114   acl_main_t *am = &acl_main;
115   acl_list_t *a;
116   acl_rule_t *r;
117   acl_rule_t *acl_new_rules;
118   int i;
119
120   if (*acl_list_index != ~0)
121     {
122       /* They supplied some number, let's see if this ACL exists */
123       if (pool_is_free_index (am->acls, *acl_list_index))
124         {
125           /* tried to replace a non-existent ACL, no point doing anything */
126           return -1;
127         }
128     }
129
130   /* Create and populate the rules */
131   acl_new_rules = clib_mem_alloc_aligned (sizeof (acl_rule_t) * count,
132                                           CLIB_CACHE_LINE_BYTES);
133   if (!acl_new_rules)
134     {
135       /* Could not allocate rules. New or existing ACL - bail out regardless */
136       return -1;
137     }
138
139   for (i = 0; i < count; i++)
140     {
141       r = &acl_new_rules[i];
142       r->is_permit = rules[i].is_permit;
143       r->is_ipv6 = rules[i].is_ipv6;
144       if (r->is_ipv6)
145         {
146           memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src));
147           memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst));
148         }
149       else
150         {
151           memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4));
152           memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4));
153         }
154       r->src_prefixlen = rules[i].src_ip_prefix_len;
155       r->dst_prefixlen = rules[i].dst_ip_prefix_len;
156       r->proto = rules[i].proto;
157       r->src_port_or_type_first = ntohs ( rules[i].srcport_or_icmptype_first );
158       r->src_port_or_type_last = ntohs ( rules[i].srcport_or_icmptype_last );
159       r->dst_port_or_code_first = ntohs ( rules[i].dstport_or_icmpcode_first );
160       r->dst_port_or_code_last = ntohs ( rules[i].dstport_or_icmpcode_last );
161       r->tcp_flags_value = rules[i].tcp_flags_value;
162       r->tcp_flags_mask = rules[i].tcp_flags_mask;
163     }
164
165   if (~0 == *acl_list_index)
166     {
167       /* Get ACL index */
168       pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
169       memset (a, 0, sizeof (*a));
170       /* Will return the newly allocated ACL index */
171       *acl_list_index = a - am->acls;
172     }
173   else
174     {
175       a = am->acls + *acl_list_index;
176       /* Get rid of the old rules */
177       clib_mem_free (a->rules);
178     }
179   a->rules = acl_new_rules;
180   a->count = count;
181   memcpy (a->tag, tag, sizeof (a->tag));
182
183   return 0;
184 }
185
186 static int
187 acl_del_list (u32 acl_list_index)
188 {
189   acl_main_t *am = &acl_main;
190   acl_list_t *a;
191   int i, ii;
192   if (pool_is_free_index (am->acls, acl_list_index))
193     {
194       return -1;
195     }
196
197   /* delete any references to the ACL */
198   for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++)
199     {
200       for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]);
201            /* see body */ )
202         {
203           if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii])
204             {
205               vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii);
206             }
207           else
208             {
209               ii++;
210             }
211         }
212     }
213   for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++)
214     {
215       for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]);
216            /* see body */ )
217         {
218           if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii])
219             {
220               vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii);
221             }
222           else
223             {
224               ii++;
225             }
226         }
227     }
228
229   /* now we can delete the ACL itself */
230   a = &am->acls[acl_list_index];
231   if (a->rules)
232     {
233       clib_mem_free (a->rules);
234     }
235   pool_put (am->acls, a);
236   return 0;
237 }
238
239 /* Some aids in ASCII graphing the content */
240 #define XX "\377"
241 #define __ "\000"
242 #define _(x)
243 #define v
244
245 u8 ip4_5tuple_mask[] =
246 _("             dmac               smac            etype ")
247 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
248   _("        v ihl totlen   ")
249   _(0x0000)
250   __ __ __ __
251   _("        ident fl+fo    ")
252   _(0x0004)
253   __ __ __ __
254   _("       ttl pr checksum ")
255   _(0x0008)
256   __ XX __ __
257   _("        src address    ")
258   _(0x000C)
259   XX XX XX XX
260   _("        dst address    ")
261   _(0x0010)
262   XX XX XX XX
263   _("L4 T/U  sport dport    ")
264   _(tcpudp)
265   XX XX XX XX
266   _(padpad)
267   __ __ __ __
268   _(padpad)
269   __ __ __ __
270   _(padeth)
271   __ __;
272
273      u8 ip6_5tuple_mask[] =
274        _("             dmac               smac            etype ")
275   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
276   _("        v  tc + flow ")
277   _(0x0000) __ __ __ __
278   _("        plen  nh hl  ")
279   _(0x0004) __ __ XX __
280   _("        src address  ")
281   _(0x0008) XX XX XX XX
282   _(0x000C) XX XX XX XX
283   _(0x0010) XX XX XX XX
284   _(0x0014) XX XX XX XX
285   _("        dst address  ")
286   _(0x0018) XX XX XX XX
287   _(0x001C) XX XX XX XX
288   _(0x0020) XX XX XX XX
289   _(0x0024) XX XX XX XX
290   _("L4T/U  sport dport   ")
291   _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
292
293 #undef XX
294 #undef __
295 #undef _
296 #undef v
297
298      static int count_skip (u8 * p, u32 size)
299 {
300   u64 *p64 = (u64 *) p;
301   /* Be tolerant to null pointer */
302   if (0 == p)
303     return 0;
304
305   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
306     {
307       p64++;
308     }
309   return (p64 - (u64 *) p) / 2;
310 }
311
312 static int
313 acl_classify_add_del_table_big (vnet_classify_main_t * cm, u8 * mask,
314                             u32 mask_len, u32 next_table_index,
315                             u32 miss_next_index, u32 * table_index,
316                             int is_add)
317 {
318   u32 nbuckets = 65536;
319   u32 memory_size = 2 << 30;
320   u32 skip = count_skip (mask, mask_len);
321   u32 match = (mask_len / 16) - skip;
322   u8 *skip_mask_ptr = mask + 16 * skip;
323   u32 current_data_flag = 0;
324   int current_data_offset = 0;
325
326   if (0 == match)
327     match = 1;
328
329   return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
330                                       memory_size, skip, match,
331                                       next_table_index, miss_next_index,
332                                       table_index, current_data_flag,
333                                       current_data_offset, is_add,
334                                       1 /* delete_chain */);
335 }
336
337 static int
338 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
339                             u32 mask_len, u32 next_table_index,
340                             u32 miss_next_index, u32 * table_index,
341                             int is_add)
342 {
343   u32 nbuckets = 32;
344   u32 memory_size = 2 << 20;
345   u32 skip = count_skip (mask, mask_len);
346   u32 match = (mask_len / 16) - skip;
347   u8 *skip_mask_ptr = mask + 16 * skip;
348   u32 current_data_flag = 0;
349   int current_data_offset = 0;
350
351   if (0 == match)
352     match = 1;
353
354   return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
355                                       memory_size, skip, match,
356                                       next_table_index, miss_next_index,
357                                       table_index, current_data_flag,
358                                       current_data_offset, is_add,
359                                       1 /* delete_chain */);
360 }
361
362
363 static int
364 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
365 {
366   vnet_classify_main_t *cm = &vnet_classify_main;
367   u32 ip4_table_index = ~0;
368   u32 ip6_table_index = ~0;
369
370   vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
371                            sw_if_index, ~0);
372   vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
373                            sw_if_index, ~0);
374
375   vnet_l2_input_classify_enable_disable (sw_if_index, 0);
376
377   if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
378     {
379       ip4_table_index =
380         am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
381       am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
382       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
383                                   sizeof (ip4_5tuple_mask) - 1, ~0,
384                                   am->l2_input_classify_next_acl_ip4,
385                                   &ip4_table_index, 0);
386     }
387   if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
388     {
389       ip6_table_index =
390         am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
391       am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
392       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
393                                   sizeof (ip6_5tuple_mask) - 1, ~0,
394                                   am->l2_input_classify_next_acl_ip6,
395                                   &ip6_table_index, 0);
396     }
397
398   return 0;
399 }
400
401 static int
402 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
403 {
404   vnet_classify_main_t *cm = &vnet_classify_main;
405   u32 ip4_table_index = ~0;
406   u32 ip6_table_index = ~0;
407
408   vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
409                            sw_if_index, ~0);
410   vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
411                            sw_if_index, ~0);
412
413   vnet_l2_output_classify_enable_disable (sw_if_index, 0);
414
415   if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
416     {
417       ip4_table_index =
418         am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
419       am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
420       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
421                                   sizeof (ip4_5tuple_mask) - 1, ~0,
422                                   am->l2_output_classify_next_acl_ip4,
423                                   &ip4_table_index, 0);
424     }
425   if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
426     {
427       ip6_table_index =
428         am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
429       am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
430       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
431                                   sizeof (ip6_5tuple_mask) - 1, ~0,
432                                   am->l2_output_classify_next_acl_ip6,
433                                   &ip6_table_index, 0);
434     }
435
436   return 0;
437 }
438
439 static int
440 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
441 {
442   vnet_classify_main_t *cm = &vnet_classify_main;
443   u32 ip4_table_index = ~0;
444   u32 ip6_table_index = ~0;
445   int rv;
446
447   /* in case there were previous tables attached */
448   acl_unhook_l2_input_classify (am, sw_if_index);
449   rv =
450     acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
451                                 sizeof (ip4_5tuple_mask) - 1, ~0,
452                                 am->l2_input_classify_next_acl_ip4,
453                                 &ip4_table_index, 1);
454   if (rv)
455     return rv;
456   rv =
457     acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
458                                 sizeof (ip6_5tuple_mask) - 1, ~0,
459                                 am->l2_input_classify_next_acl_ip6,
460                                 &ip6_table_index, 1);
461   if (rv)
462     {
463       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
464                                   sizeof (ip4_5tuple_mask) - 1, ~0,
465                                   am->l2_input_classify_next_acl_ip4,
466                                   &ip4_table_index, 0);
467       return rv;
468     }
469   rv =
470     vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
471                                        ip6_table_index, ~0);
472   clib_warning
473     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
474      sw_if_index, ip4_table_index, ip6_table_index);
475   if (rv)
476     {
477       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
478                                   sizeof (ip6_5tuple_mask) - 1, ~0,
479                                   am->l2_input_classify_next_acl_ip6,
480                                   &ip6_table_index, 0);
481       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
482                                   sizeof (ip4_5tuple_mask) - 1, ~0,
483                                   am->l2_input_classify_next_acl_ip4,
484                                   &ip4_table_index, 0);
485       return rv;
486     }
487
488   am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
489     ip4_table_index;
490   am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
491     ip6_table_index;
492
493   vnet_l2_input_classify_enable_disable (sw_if_index, 1);
494   return rv;
495 }
496
497 static int
498 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
499 {
500   vnet_classify_main_t *cm = &vnet_classify_main;
501   u32 ip4_table_index = ~0;
502   u32 ip6_table_index = ~0;
503   int rv;
504
505   /* in case there were previous tables attached */
506   acl_unhook_l2_output_classify (am, sw_if_index);
507   rv =
508     acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
509                                 sizeof (ip4_5tuple_mask) - 1, ~0,
510                                 am->l2_output_classify_next_acl_ip4,
511                                 &ip4_table_index, 1);
512   if (rv)
513     return rv;
514   rv =
515     acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
516                                 sizeof (ip6_5tuple_mask) - 1, ~0,
517                                 am->l2_output_classify_next_acl_ip6,
518                                 &ip6_table_index, 1);
519   if (rv)
520     {
521       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
522                                   sizeof (ip4_5tuple_mask) - 1, ~0,
523                                   am->l2_output_classify_next_acl_ip4,
524                                   &ip4_table_index, 0);
525       return rv;
526     }
527   rv =
528     vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
529                                         ip6_table_index, ~0);
530   clib_warning
531     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
532      sw_if_index, ip4_table_index, ip6_table_index);
533   if (rv)
534     {
535       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
536                                   sizeof (ip6_5tuple_mask) - 1, ~0,
537                                   am->l2_output_classify_next_acl_ip6,
538                                   &ip6_table_index, 0);
539       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
540                                   sizeof (ip4_5tuple_mask) - 1, ~0,
541                                   am->l2_output_classify_next_acl_ip4,
542                                   &ip4_table_index, 0);
543       return rv;
544     }
545
546   am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
547     ip4_table_index;
548   am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
549     ip6_table_index;
550
551   vnet_l2_output_classify_enable_disable (sw_if_index, 1);
552   return rv;
553 }
554
555
556
557 int
558 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
559                                  int enable_disable)
560 {
561   int rv;
562
563   /* Utterly wrong? */
564   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
565                           sw_if_index))
566     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
567
568   acl_fa_enable_disable(sw_if_index, 1, enable_disable);
569
570   if (enable_disable)
571     {
572       rv = acl_hook_l2_input_classify (am, sw_if_index);
573     }
574   else
575     {
576       rv = acl_unhook_l2_input_classify (am, sw_if_index);
577     }
578
579   return rv;
580 }
581
582 int
583 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
584                                   int enable_disable)
585 {
586   int rv;
587
588   /* Utterly wrong? */
589   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
590                           sw_if_index))
591     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
592
593   acl_fa_enable_disable(sw_if_index, 0, enable_disable);
594
595   if (enable_disable)
596     {
597       rv = acl_hook_l2_output_classify (am, sw_if_index);
598     }
599   else
600     {
601       rv = acl_unhook_l2_output_classify (am, sw_if_index);
602     }
603
604   return rv;
605 }
606
607
608 static int
609 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
610 {
611   acl_main_t *am = &acl_main;
612   if (is_input)
613     {
614       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
615       vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
616                1);
617       acl_interface_in_enable_disable (am, sw_if_index, 1);
618     }
619   else
620     {
621       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
622       vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
623                &acl_list_index, 1);
624       acl_interface_out_enable_disable (am, sw_if_index, 1);
625     }
626   return 0;
627 }
628
629 static int
630 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
631 {
632   acl_main_t *am = &acl_main;
633   int i;
634   int rv = -1;
635   if (is_input)
636     {
637       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
638       for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
639            i++)
640         {
641           if (acl_list_index ==
642               am->input_acl_vec_by_sw_if_index[sw_if_index][i])
643             {
644               vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
645               rv = 0;
646               break;
647             }
648         }
649       if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
650         {
651           acl_interface_in_enable_disable (am, sw_if_index, 0);
652         }
653     }
654   else
655     {
656       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
657       for (i = 0;
658            i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
659         {
660           if (acl_list_index ==
661               am->output_acl_vec_by_sw_if_index[sw_if_index][i])
662             {
663               vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
664               rv = 0;
665               break;
666             }
667         }
668       if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
669         {
670           acl_interface_out_enable_disable (am, sw_if_index, 0);
671         }
672     }
673   return rv;
674 }
675
676 static void
677 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
678 {
679   acl_main_t *am = &acl_main;
680   if (is_input)
681     {
682       acl_interface_in_enable_disable (am, sw_if_index, 0);
683       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
684       vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
685     }
686   else
687     {
688       acl_interface_out_enable_disable (am, sw_if_index, 0);
689       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
690       vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
691     }
692 }
693
694 static int
695 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
696                                  u32 acl_list_index)
697 {
698   int rv = -1;
699   if (is_add)
700     {
701       rv =
702         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
703     }
704   else
705     {
706       rv =
707         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
708     }
709   return rv;
710 }
711
712
713 typedef struct
714 {
715   u8 is_ipv6;
716   u8 mac_mask[6];
717   u8 prefix_len;
718   u32 count;
719   u32 table_index;
720   u32 arp_table_index;
721 } macip_match_type_t;
722
723 static u32
724 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
725                        u8 is_ipv6)
726 {
727   u32 i;
728   if (mv)
729     {
730       for (i = 0; i < vec_len (mv); i++)
731         {
732           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
733               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
734             {
735               return i;
736             }
737         }
738     }
739   return ~0;
740 }
741
742
743 /* Get metric used to sort match types.
744    The more specific and the more often seen - the bigger the metric */
745 static int
746 match_type_metric (macip_match_type_t * m)
747 {
748   /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */
749   return m->prefix_len + m->is_ipv6 + 10 * m->count;
750 }
751
752 static int
753 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
754 {
755   /* Ascending sort based on the metric values */
756   return match_type_metric (m1) - match_type_metric (m2);
757 }
758
759 /* Get the offset of L3 source within ethernet packet */
760 static int
761 get_l3_src_offset(int is6)
762 {
763   if(is6)
764     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
765   else
766     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
767 }
768
769 static int
770 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
771 {
772   macip_match_type_t *mvec = NULL;
773   macip_match_type_t *mt;
774   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
775   int i;
776   u32 match_type_index;
777   u32 last_table;
778   u8 mask[5 * 16];
779   vnet_classify_main_t *cm = &vnet_classify_main;
780
781   /* Count the number of different types of rules */
782   for (i = 0; i < a->count; i++)
783     {
784       if (~0 ==
785           (match_type_index =
786            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
787                                   a->rules[i].src_prefixlen,
788                                   a->rules[i].is_ipv6)))
789         {
790           match_type_index = vec_len (mvec);
791           vec_validate (mvec, match_type_index);
792           memcpy (mvec[match_type_index].mac_mask,
793                   a->rules[match_type_index].src_mac_mask, 6);
794           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
795           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
796           mvec[match_type_index].table_index = ~0;
797         }
798       mvec[match_type_index].count++;
799     }
800   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
801   vec_sort_with_function (mvec, match_type_compare);
802   /* Create the classifier tables */
803   last_table = ~0;
804   /* First add ARP tables */
805   vec_foreach (mt, mvec)
806   {
807     int mask_len;
808     int is6 = mt->is_ipv6;
809
810     mt->arp_table_index = ~0;
811     if (!is6)
812       {
813         memset (mask, 0, sizeof (mask));
814         memcpy (&mask[6], mt->mac_mask, 6);
815         memset (&mask[12], 0xff, 2); /* ethernet protocol */
816         memcpy (&mask[14 + 8], mt->mac_mask, 6);
817
818         for (i = 0; i < (mt->prefix_len / 8); i++)
819           mask[14 + 14 + i] = 0xff;
820         if (mt->prefix_len % 8)
821           mask[14 + 14 + (mt->prefix_len / 8)] = 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
822
823         mask_len = ((14 + 14 + ((mt->prefix_len+7) / 8) +
824                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
825         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
826                                (~0 == last_table) ? 0 : ~0, &mt->arp_table_index,
827                                1);
828         last_table = mt->arp_table_index;
829       }
830   }
831   /* Now add IP[46] tables */
832   vec_foreach (mt, mvec)
833   {
834     int mask_len;
835     int is6 = mt->is_ipv6;
836     int l3_src_offs = get_l3_src_offset(is6);
837     memset (mask, 0, sizeof (mask));
838     memcpy (&mask[6], mt->mac_mask, 6);
839     for (i = 0; i < (mt->prefix_len / 8); i++)
840       {
841         mask[l3_src_offs + i] = 0xff;
842       }
843     if (mt->prefix_len % 8)
844       {
845         mask[l3_src_offs + (mt->prefix_len / 8)] =
846           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
847       }
848     /*
849      * Round-up the number of bytes needed to store the prefix,
850      * and round up the number of vectors too
851      */
852     mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) +
853                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
854     acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
855                                 (~0 == last_table) ? 0 : ~0, &mt->table_index,
856                                 1);
857     last_table = mt->table_index;
858   }
859   a->ip4_table_index = ~0;
860   a->ip6_table_index = ~0;
861   a->l2_table_index = last_table;
862
863   /* Populate the classifier tables with rules from the MACIP ACL */
864   for (i = 0; i < a->count; i++)
865     {
866       u32 action = 0;
867       u32 metadata = 0;
868       int is6 = a->rules[i].is_ipv6;
869       int l3_src_offs = get_l3_src_offset(is6);
870       memset (mask, 0, sizeof (mask));
871       memcpy (&mask[6], a->rules[i].src_mac, 6);
872       memset (&mask[12], 0xff, 2); /* ethernet protocol */
873       if (is6)
874         {
875           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
876           mask[12] = 0x86;
877           mask[13] = 0xdd;
878         }
879       else
880         {
881           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
882           mask[12] = 0x08;
883           mask[13] = 0x00;
884         }
885       match_type_index =
886         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
887                                a->rules[i].src_prefixlen,
888                                a->rules[i].is_ipv6);
889       /* add session to table mvec[match_type_index].table_index; */
890       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
891                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
892                                      0, action, metadata, 1);
893       /* add ARP table entry too */
894       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
895         {
896           memset (mask, 0, sizeof (mask));
897           memcpy (&mask[6], a->rules[i].src_mac, 6);
898           mask[12] = 0x08;
899           mask[13] = 0x06;
900           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
901           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
902           vnet_classify_add_del_session (cm, mvec[match_type_index].arp_table_index,
903                                     mask, a->rules[i].is_permit ? ~0 : 0, i,
904                                     0, action, metadata, 1);
905         }
906     }
907   return 0;
908 }
909
910 static void
911 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
912 {
913   vnet_classify_main_t *cm = &vnet_classify_main;
914   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
915
916   if (a->ip4_table_index != ~0)
917     {
918       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
919       a->ip4_table_index = ~0;
920     }
921   if (a->ip6_table_index != ~0)
922     {
923       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
924       a->ip6_table_index = ~0;
925     }
926   if (a->l2_table_index != ~0)
927     {
928       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
929       a->l2_table_index = ~0;
930     }
931 }
932
933 static int
934 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
935                     u32 * acl_list_index, u8 * tag)
936 {
937   acl_main_t *am = &acl_main;
938   macip_acl_list_t *a;
939   macip_acl_rule_t *r;
940   macip_acl_rule_t *acl_new_rules;
941   int i;
942
943   /* Create and populate the rules */
944   acl_new_rules = clib_mem_alloc_aligned (sizeof (macip_acl_rule_t) * count,
945                                           CLIB_CACHE_LINE_BYTES);
946   if (!acl_new_rules)
947     {
948       /* Could not allocate rules. New or existing ACL - bail out regardless */
949       return -1;
950     }
951
952   for (i = 0; i < count; i++)
953     {
954       r = &acl_new_rules[i];
955       r->is_permit = rules[i].is_permit;
956       r->is_ipv6 = rules[i].is_ipv6;
957       memcpy (&r->src_mac, rules[i].src_mac, 6);
958       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
959       if(rules[i].is_ipv6)
960         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
961       else
962         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
963       r->src_prefixlen = rules[i].src_ip_prefix_len;
964     }
965
966   /* Get ACL index */
967   pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
968   memset (a, 0, sizeof (*a));
969   /* Will return the newly allocated ACL index */
970   *acl_list_index = a - am->macip_acls;
971
972   a->rules = acl_new_rules;
973   a->count = count;
974   memcpy (a->tag, tag, sizeof (a->tag));
975
976   /* Create and populate the classifer tables */
977   macip_create_classify_tables (am, *acl_list_index);
978
979   return 0;
980 }
981
982
983 /* No check for validity of sw_if_index - the callers were supposed to validate */
984
985 static int
986 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
987 {
988   int rv;
989   u32 macip_acl_index;
990   macip_acl_list_t *a;
991   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
992   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
993   /* No point in deleting MACIP ACL which is not applied */
994   if (~0 == macip_acl_index)
995     return -1;
996   a = &am->macip_acls[macip_acl_index];
997   /* remove the classifier tables off the interface L2 ACL */
998   rv =
999     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1000                               a->ip6_table_index, a->l2_table_index, 0);
1001   /* Unset the MACIP ACL index */
1002   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1003   return rv;
1004 }
1005
1006 /* No check for validity of sw_if_index - the callers were supposed to validate */
1007
1008 static int
1009 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1010                              u32 macip_acl_index)
1011 {
1012   macip_acl_list_t *a;
1013   int rv;
1014   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1015     {
1016       return -1;
1017     }
1018   a = &am->macip_acls[macip_acl_index];
1019   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1020   /* If there already a MACIP ACL applied, unapply it */
1021   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1022     macip_acl_interface_del_acl(am, sw_if_index);
1023   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1024   /* Apply the classifier tables for L2 ACLs */
1025   rv =
1026     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1027                               a->ip6_table_index, a->l2_table_index, 1);
1028   return rv;
1029 }
1030
1031 static int
1032 macip_acl_del_list (u32 acl_list_index)
1033 {
1034   acl_main_t *am = &acl_main;
1035   macip_acl_list_t *a;
1036   int i;
1037   if (pool_is_free_index (am->macip_acls, acl_list_index))
1038     {
1039       return -1;
1040     }
1041
1042   /* delete any references to the ACL */
1043   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1044     {
1045       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1046         {
1047           macip_acl_interface_del_acl (am, i);
1048         }
1049     }
1050
1051   /* Now that classifier tables are detached, clean them up */
1052   macip_destroy_classify_tables (am, acl_list_index);
1053
1054   /* now we can delete the ACL itself */
1055   a = &am->macip_acls[acl_list_index];
1056   if (a->rules)
1057     {
1058       clib_mem_free (a->rules);
1059     }
1060   pool_put (am->macip_acls, a);
1061   return 0;
1062 }
1063
1064
1065 static int
1066 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1067                                  u32 acl_list_index)
1068 {
1069   acl_main_t *am = &acl_main;
1070   int rv = -1;
1071   if (is_add)
1072     {
1073       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1074     }
1075   else
1076     {
1077       rv = macip_acl_interface_del_acl (am, sw_if_index);
1078     }
1079   return rv;
1080 }
1081
1082 /*
1083  * If the client does not allocate enough memory for a variable-length
1084  * message, and then proceed to use it as if the full memory allocated,
1085  * absent the check we happily consume that on the VPP side, and go
1086  * along as if nothing happened. However, the resulting
1087  * effects range from just garbage in the API decode
1088  * (because the decoder snoops too far), to potential memory
1089  * corruptions.
1090  *
1091  * This verifies that the actual length of the message is
1092  * at least expected_len, and complains loudly if it is not.
1093  *
1094  * A failing check here is 100% a software bug on the API user side,
1095  * so we might as well yell.
1096  *
1097  */
1098 static int verify_message_len(void *mp, u32 expected_len, char *where)
1099 {
1100   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1101   if (supplied_len < expected_len) {
1102       clib_warning("%s: Supplied message length %d is less than expected %d",
1103                    where, supplied_len, expected_len);
1104       return 0;
1105   } else {
1106       return 1;
1107   }
1108 }
1109
1110 /* API message handler */
1111 static void
1112 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1113 {
1114   vl_api_acl_add_replace_reply_t *rmp;
1115   acl_main_t *am = &acl_main;
1116   int rv;
1117   u32 acl_list_index = ntohl (mp->acl_index);
1118   u32 acl_count = ntohl (mp->count);
1119   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1120
1121   if (verify_message_len(mp, expected_len, "acl_add_replace")) {
1122       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1123   } else {
1124       rv = VNET_API_ERROR_INVALID_VALUE;
1125   }
1126
1127   /* *INDENT-OFF* */
1128   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1129   ({
1130     rmp->acl_index = htonl(acl_list_index);
1131   }));
1132   /* *INDENT-ON* */
1133 }
1134
1135 static void
1136 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1137 {
1138   acl_main_t *am = &acl_main;
1139   vl_api_acl_del_reply_t *rmp;
1140   int rv;
1141
1142   rv = acl_del_list (ntohl (mp->acl_index));
1143
1144   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1145 }
1146
1147 static void
1148 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1149 {
1150   acl_main_t *am = &acl_main;
1151   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1152   u32 sw_if_index = ntohl (mp->sw_if_index);
1153   vl_api_acl_interface_add_del_reply_t *rmp;
1154   int rv = -1;
1155
1156   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1157     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1158   else
1159     rv =
1160       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1161                                      mp->is_input, ntohl (mp->acl_index));
1162
1163   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1164 }
1165
1166 static void
1167 vl_api_acl_interface_set_acl_list_t_handler
1168   (vl_api_acl_interface_set_acl_list_t * mp)
1169 {
1170   acl_main_t *am = &acl_main;
1171   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1172   int rv = 0;
1173   int i;
1174   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1175   u32 sw_if_index = ntohl (mp->sw_if_index);
1176
1177   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1178     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1179   else
1180     {
1181       acl_interface_reset_inout_acls (sw_if_index, 0);
1182       acl_interface_reset_inout_acls (sw_if_index, 1);
1183
1184       for (i = 0; i < mp->count; i++)
1185         {
1186           acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1187                                        ntohl (mp->acls[i]));
1188         }
1189     }
1190
1191   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1192 }
1193
1194 static void
1195 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1196 {
1197   api_rule->is_permit = r->is_permit;
1198   api_rule->is_ipv6 = r->is_ipv6;
1199   if(r->is_ipv6)
1200     {
1201       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1202       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1203     }
1204   else
1205     {
1206       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1207       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1208     }
1209   api_rule->src_ip_prefix_len = r->src_prefixlen;
1210   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1211   api_rule->proto = r->proto;
1212   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1213   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1214   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1215   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1216   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1217   api_rule->tcp_flags_value = r->tcp_flags_value;
1218 }
1219
1220 static void
1221 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1222                   acl_list_t * acl, u32 context)
1223 {
1224   vl_api_acl_details_t *mp;
1225   vl_api_acl_rule_t *rules;
1226   int i;
1227   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1228
1229   mp = vl_msg_api_alloc (msg_size);
1230   memset (mp, 0, msg_size);
1231   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1232
1233   /* fill in the message */
1234   mp->context = context;
1235   mp->count = htonl (acl->count);
1236   mp->acl_index = htonl (acl - am->acls);
1237   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1238   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1239   rules = mp->r;
1240   for (i = 0; i < acl->count; i++)
1241     {
1242       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1243     }
1244
1245   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1246   vl_msg_api_send_shmem (q, (u8 *) & mp);
1247 }
1248
1249
1250 static void
1251 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1252 {
1253   acl_main_t *am = &acl_main;
1254   u32 acl_index;
1255   acl_list_t *acl;
1256
1257   int rv = -1;
1258   unix_shared_memory_queue_t *q;
1259
1260   q = vl_api_client_index_to_input_queue (mp->client_index);
1261   if (q == 0)
1262     {
1263       return;
1264     }
1265
1266   if (mp->acl_index == ~0)
1267     {
1268     /* *INDENT-OFF* */
1269     /* Just dump all ACLs */
1270     pool_foreach (acl, am->acls,
1271     ({
1272       send_acl_details(am, q, acl, mp->context);
1273     }));
1274     /* *INDENT-ON* */
1275     }
1276   else
1277     {
1278       acl_index = ntohl (mp->acl_index);
1279       if (!pool_is_free_index (am->acls, acl_index))
1280         {
1281           acl = &am->acls[acl_index];
1282           send_acl_details (am, q, acl, mp->context);
1283         }
1284     }
1285
1286   if (rv == -1)
1287     {
1288       /* FIXME API: should we signal an error here at all ? */
1289       return;
1290     }
1291 }
1292
1293 static void
1294 send_acl_interface_list_details (acl_main_t * am,
1295                                  unix_shared_memory_queue_t * q,
1296                                  u32 sw_if_index, u32 context)
1297 {
1298   vl_api_acl_interface_list_details_t *mp;
1299   int msg_size;
1300   int n_input;
1301   int n_output;
1302   int count;
1303   int i = 0;
1304
1305   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1306   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1307
1308   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1309   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1310   count = n_input + n_output;
1311
1312   msg_size = sizeof (*mp);
1313   msg_size += sizeof (mp->acls[0]) * count;
1314
1315   mp = vl_msg_api_alloc (msg_size);
1316   memset (mp, 0, msg_size);
1317   mp->_vl_msg_id =
1318     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1319
1320   /* fill in the message */
1321   mp->context = context;
1322   mp->sw_if_index = htonl (sw_if_index);
1323   mp->count = count;
1324   mp->n_input = n_input;
1325   for (i = 0; i < n_input; i++)
1326     {
1327       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1328     }
1329   for (i = 0; i < n_output; i++)
1330     {
1331       mp->acls[n_input + i] =
1332         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1333     }
1334
1335   vl_msg_api_send_shmem (q, (u8 *) & mp);
1336 }
1337
1338 static void
1339 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1340                                           mp)
1341 {
1342   acl_main_t *am = &acl_main;
1343   vnet_sw_interface_t *swif;
1344   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1345
1346   u32 sw_if_index;
1347   unix_shared_memory_queue_t *q;
1348
1349   q = vl_api_client_index_to_input_queue (mp->client_index);
1350   if (q == 0)
1351     {
1352       return;
1353     }
1354
1355   if (mp->sw_if_index == ~0)
1356     {
1357     /* *INDENT-OFF* */
1358     pool_foreach (swif, im->sw_interfaces,
1359     ({
1360       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1361     }));
1362     /* *INDENT-ON* */
1363     }
1364   else
1365     {
1366       sw_if_index = ntohl (mp->sw_if_index);
1367       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1368         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1369     }
1370 }
1371
1372 /* MACIP ACL API handlers */
1373
1374 static void
1375 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1376 {
1377   vl_api_macip_acl_add_reply_t *rmp;
1378   acl_main_t *am = &acl_main;
1379   int rv;
1380   u32 acl_list_index = ~0;
1381   u32 acl_count = ntohl (mp->count);
1382   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1383
1384   if (verify_message_len(mp, expected_len, "macip_acl_add")) {
1385       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1386   } else {
1387       rv = VNET_API_ERROR_INVALID_VALUE;
1388   }
1389
1390   /* *INDENT-OFF* */
1391   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1392   ({
1393     rmp->acl_index = htonl(acl_list_index);
1394   }));
1395   /* *INDENT-ON* */
1396 }
1397
1398 static void
1399 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1400 {
1401   acl_main_t *am = &acl_main;
1402   vl_api_macip_acl_del_reply_t *rmp;
1403   int rv;
1404
1405   rv = macip_acl_del_list (ntohl (mp->acl_index));
1406
1407   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1408 }
1409
1410 static void
1411 vl_api_macip_acl_interface_add_del_t_handler
1412   (vl_api_macip_acl_interface_add_del_t * mp)
1413 {
1414   acl_main_t *am = &acl_main;
1415   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1416   int rv = -1;
1417   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1418   u32 sw_if_index = ntohl (mp->sw_if_index);
1419
1420   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1421     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1422   else
1423     rv =
1424       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1425                                      ntohl (mp->acl_index));
1426
1427   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1428 }
1429
1430 static void
1431 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1432                         macip_acl_list_t * acl, u32 context)
1433 {
1434   vl_api_macip_acl_details_t *mp;
1435   vl_api_macip_acl_rule_t *rules;
1436   macip_acl_rule_t *r;
1437   int i;
1438   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1439
1440   mp = vl_msg_api_alloc (msg_size);
1441   memset (mp, 0, msg_size);
1442   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1443
1444   /* fill in the message */
1445   mp->context = context;
1446   if (acl)
1447     {
1448       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1449       mp->count = htonl (acl->count);
1450       mp->acl_index = htonl (acl - am->macip_acls);
1451       rules = mp->r;
1452       for (i = 0; i < acl->count; i++)
1453         {
1454           r = &acl->rules[i];
1455           rules[i].is_permit = r->is_permit;
1456           rules[i].is_ipv6 = r->is_ipv6;
1457           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1458           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1459                   sizeof (r->src_mac_mask));
1460           if (r->is_ipv6)
1461             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1462                   sizeof (r->src_ip_addr.ip6));
1463           else
1464             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1465                   sizeof (r->src_ip_addr.ip4));
1466           rules[i].src_ip_prefix_len = r->src_prefixlen;
1467         }
1468     }
1469   else
1470     {
1471       /* No martini, no party - no ACL applied to this interface. */
1472       mp->acl_index = ~0;
1473       mp->count = 0;
1474     }
1475
1476   vl_msg_api_send_shmem (q, (u8 *) & mp);
1477 }
1478
1479
1480 static void
1481 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1482 {
1483   acl_main_t *am = &acl_main;
1484   macip_acl_list_t *acl;
1485
1486   unix_shared_memory_queue_t *q;
1487
1488   q = vl_api_client_index_to_input_queue (mp->client_index);
1489   if (q == 0)
1490     {
1491       return;
1492     }
1493
1494   if (mp->acl_index == ~0)
1495     {
1496       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1497       pool_foreach (acl, am->macip_acls, (
1498                                            {
1499                                            send_macip_acl_details (am, q, acl,
1500                                                                    mp->
1501                                                                    context);}
1502                     ));
1503       /* *INDENT-ON* */
1504     }
1505   else
1506     {
1507       u32 acl_index = ntohl (mp->acl_index);
1508       if (!pool_is_free_index (am->macip_acls, acl_index))
1509         {
1510           acl = &am->macip_acls[acl_index];
1511           send_macip_acl_details (am, q, acl, mp->context);
1512         }
1513     }
1514 }
1515
1516 static void
1517 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1518                                           mp)
1519 {
1520   acl_main_t *am = &acl_main;
1521   vl_api_macip_acl_interface_get_reply_t *rmp;
1522   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1523   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1524   unix_shared_memory_queue_t *q;
1525   int i;
1526
1527   q = vl_api_client_index_to_input_queue (mp->client_index);
1528   if (q == 0)
1529     {
1530       return;
1531     }
1532
1533   rmp = vl_msg_api_alloc (msg_size);
1534   memset (rmp, 0, msg_size);
1535   rmp->_vl_msg_id =
1536     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1537   rmp->context = mp->context;
1538   rmp->count = htonl (count);
1539   for (i = 0; i < count; i++)
1540     {
1541       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1542     }
1543
1544   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1545 }
1546
1547 /* Set up the API message handling tables */
1548 static clib_error_t *
1549 acl_plugin_api_hookup (vlib_main_t * vm)
1550 {
1551   acl_main_t *am = &acl_main;
1552 #define _(N,n)                                                  \
1553     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
1554                            #n,                                  \
1555                            vl_api_##n##_t_handler,              \
1556                            vl_noop_handler,                     \
1557                            vl_api_##n##_t_endian,               \
1558                            vl_api_##n##_t_print,                \
1559                            sizeof(vl_api_##n##_t), 1);
1560   foreach_acl_plugin_api_msg;
1561 #undef _
1562
1563   return 0;
1564 }
1565
1566 #define vl_msg_name_crc_list
1567 #include <acl/acl_all_api_h.h>
1568 #undef vl_msg_name_crc_list
1569
1570 static void
1571 setup_message_id_table (acl_main_t * am, api_main_t * apim)
1572 {
1573 #define _(id,n,crc) \
1574   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
1575   foreach_vl_msg_name_crc_acl;
1576 #undef _
1577 }
1578
1579 static void
1580 acl_setup_fa_nodes (void)
1581 {
1582   vlib_main_t *vm = vlib_get_main ();
1583   acl_main_t *am = &acl_main;
1584   vlib_node_t *n, *n4, *n6;
1585
1586   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1587   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
1588   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
1589
1590
1591   am->l2_input_classify_next_acl_ip4 =
1592     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1593   am->l2_input_classify_next_acl_ip6 =
1594     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1595
1596   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
1597                                l2input_get_feat_names (),
1598                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
1599
1600   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
1601                                l2input_get_feat_names (),
1602                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
1603
1604
1605   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1606   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
1607   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
1608
1609   am->l2_output_classify_next_acl_ip4 =
1610     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1611   am->l2_output_classify_next_acl_ip6 =
1612     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1613
1614   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
1615                                l2output_get_feat_names (),
1616                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
1617
1618   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
1619                                l2output_get_feat_names (),
1620                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
1621 }
1622
1623 static void
1624 acl_set_timeout_sec(int timeout_type, u32 value)
1625 {
1626   acl_main_t *am = &acl_main;
1627   clib_time_t *ct = &am->vlib_main->clib_time;
1628
1629   if (timeout_type < ACL_N_TIMEOUTS) {
1630     am->session_timeout_sec[timeout_type] = value;
1631   } else {
1632     clib_warning("Unknown timeout type %d", timeout_type);
1633     return;
1634   }
1635   am->session_timeout[timeout_type] = (u64)(((f64)value)/ct->seconds_per_clock);
1636 }
1637
1638 static void
1639 acl_set_session_max_entries(u32 value)
1640 {
1641   acl_main_t *am = &acl_main;
1642   am->fa_conn_table_max_entries = value;
1643 }
1644
1645 static int
1646 acl_set_skip_ipv6_eh(u32 eh, u32 value)
1647 {
1648   acl_main_t *am = &acl_main;
1649   if ((eh < 256) && (value < 2))
1650     {
1651       am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, eh, value);
1652       return 1;
1653     }
1654   else
1655     return 0;
1656 }
1657
1658
1659 static clib_error_t *
1660 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1661 {
1662   acl_main_t *am = &acl_main;
1663   if (0 == is_add) {
1664     vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
1665                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, sw_if_index);
1666     /* also unapply any ACLs in case the users did not do so. */
1667     macip_acl_interface_del_acl(am, sw_if_index);
1668     acl_interface_reset_inout_acls (sw_if_index, 0);
1669     acl_interface_reset_inout_acls (sw_if_index, 1);
1670   }
1671   return 0;
1672 }
1673
1674 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
1675
1676 static clib_error_t *
1677 acl_set_aclplugin_fn (vlib_main_t * vm,
1678                               unformat_input_t * input,
1679                               vlib_cli_command_t * cmd)
1680 {
1681   clib_error_t *error = 0;
1682   u32 timeout = 0;
1683   u32 val = 0;
1684   u32 eh_val = 0;
1685   uword memory_size = 0;
1686   acl_main_t *am = &acl_main;
1687
1688   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val)) {
1689     if(!acl_set_skip_ipv6_eh(eh_val, val)) {
1690       error = clib_error_return(0, "expecting eh=0..255, value=0..1");
1691     }
1692     goto done;
1693   }
1694   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
1695     {
1696       am->l4_match_nonfirst_fragment = (val != 0);
1697       goto done;
1698     }
1699   if (unformat (input, "session")) {
1700     if (unformat (input, "clear")) {
1701       acl_main_t *am = &acl_main;
1702       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
1703                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
1704           goto done;
1705     }
1706     if (unformat (input, "table")) {
1707       /* The commands here are for tuning/testing. No user-serviceable parts inside */
1708       if (unformat (input, "max-entries")) {
1709         if (!unformat(input, "%u", &val)) {
1710           error = clib_error_return(0,
1711                                     "expecting maximum number of entries, got `%U`",
1712                                     format_unformat_error, input);
1713           goto done;
1714         } else {
1715           acl_set_session_max_entries(val);
1716           goto done;
1717         }
1718       }
1719       if (unformat (input, "hash-table-buckets")) {
1720         if (!unformat(input, "%u", &val)) {
1721           error = clib_error_return(0,
1722                                     "expecting maximum number of hash table buckets, got `%U`",
1723                                     format_unformat_error, input);
1724           goto done;
1725         } else {
1726           am->fa_conn_table_hash_num_buckets = val;
1727           goto done;
1728         }
1729       }
1730       if (unformat (input, "hash-table-memory")) {
1731         if (!unformat(input, "%U", unformat_memory_size, &memory_size)) {
1732           error = clib_error_return(0,
1733                                     "expecting maximum amount of hash table memory, got `%U`",
1734                                     format_unformat_error, input);
1735           goto done;
1736         } else {
1737           am->fa_conn_table_hash_memory_size = memory_size;
1738           goto done;
1739         }
1740       }
1741       goto done;
1742     }
1743     if (unformat (input, "timeout")) {
1744       if (unformat(input, "udp")) {
1745         if(unformat(input, "idle")) {
1746           if (!unformat(input, "%u", &timeout)) {
1747             error = clib_error_return(0,
1748                                       "expecting timeout value in seconds, got `%U`",
1749                                       format_unformat_error, input);
1750             goto done;
1751           } else {
1752             acl_set_timeout_sec(ACL_TIMEOUT_UDP_IDLE, timeout);
1753             goto done;
1754           }
1755         }
1756       }
1757       if (unformat(input, "tcp")) {
1758         if(unformat(input, "idle")) {
1759           if (!unformat(input, "%u", &timeout)) {
1760             error = clib_error_return(0,
1761                                       "expecting timeout value in seconds, got `%U`",
1762                                       format_unformat_error, input);
1763             goto done;
1764           } else {
1765             acl_set_timeout_sec(ACL_TIMEOUT_TCP_IDLE, timeout);
1766             goto done;
1767           }
1768         }
1769         if(unformat(input, "transient")) {
1770           if (!unformat(input, "%u", &timeout)) {
1771             error = clib_error_return(0,
1772                                       "expecting timeout value in seconds, got `%U`",
1773                                       format_unformat_error, input);
1774             goto done;
1775           } else {
1776             acl_set_timeout_sec(ACL_TIMEOUT_TCP_TRANSIENT, timeout);
1777             goto done;
1778           }
1779         }
1780       }
1781       goto done;
1782     }
1783   }
1784 done:
1785   return error;
1786 }
1787
1788 static clib_error_t *
1789 acl_show_aclplugin_fn (vlib_main_t * vm,
1790                               unformat_input_t * input,
1791                               vlib_cli_command_t * cmd)
1792 {
1793   clib_error_t *error = 0;
1794   acl_main_t *am = &acl_main;
1795   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1796
1797   vnet_sw_interface_t *swif;
1798
1799   if (unformat (input, "sessions"))
1800     {
1801       u8 * out0 = 0;
1802       pool_foreach (swif, im->sw_interfaces,
1803       ({
1804         u32 sw_if_index =  swif->sw_if_index;
1805         u64 n_adds = sw_if_index < vec_len(am->fa_session_adds_by_sw_if_index) ? am->fa_session_adds_by_sw_if_index[sw_if_index] : 0;
1806         u64 n_dels = sw_if_index < vec_len(am->fa_session_dels_by_sw_if_index) ? am->fa_session_dels_by_sw_if_index[sw_if_index] : 0;
1807         out0 = format(out0, "sw_if_index %d: add %lu - del %lu = %lu\n", sw_if_index, n_adds, n_dels, n_adds - n_dels);
1808       }));
1809       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
1810 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
1811       foreach_fa_cleaner_counter;
1812 #undef _
1813       vlib_cli_output(vm, "\n\n%s\n\n", out0);
1814       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
1815               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
1816               am->fa_cleaner_wait_time_increment * 1000.0, ((f64)am->fa_current_cleaner_timer_wait_interval) * 1000.0/(f64)vm->clib_time.clocks_per_second);
1817
1818       vec_free(out0);
1819     }
1820   return error;
1821 }
1822
1823
1824  /* *INDENT-OFF* */
1825 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
1826     .path = "set acl-plugin",
1827     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
1828     .function = acl_set_aclplugin_fn,
1829 };
1830
1831 VLIB_CLI_COMMAND (aclplugin_show_command, static) = {
1832     .path = "show acl-plugin",
1833     .short_help = "show acl-plugin sessions",
1834     .function = acl_show_aclplugin_fn,
1835 };
1836 /* *INDENT-ON* */
1837
1838
1839
1840 static clib_error_t *
1841 acl_init (vlib_main_t * vm)
1842 {
1843   acl_main_t *am = &acl_main;
1844   clib_error_t *error = 0;
1845   memset (am, 0, sizeof (*am));
1846   am->vlib_main = vm;
1847   am->vnet_main = vnet_get_main ();
1848
1849   u8 *name = format (0, "acl_%08x%c", api_version, 0);
1850
1851   /* Ask for a correctly-sized block of API message decode slots */
1852   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
1853                                             VL_MSG_FIRST_AVAILABLE);
1854
1855   error = acl_plugin_api_hookup (vm);
1856
1857  /* Add our API messages to the global name_crc hash table */
1858   setup_message_id_table (am, &api_main);
1859
1860   vec_free (name);
1861
1862   acl_setup_fa_nodes();
1863   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
1864   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
1865   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;
1866
1867   am->fa_conn_table_hash_num_buckets = ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
1868   am->fa_conn_table_hash_memory_size = ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
1869   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
1870
1871   {
1872     u8 tt;
1873     for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
1874        am->fa_conn_list_head[tt] = ~0;
1875        am->fa_conn_list_tail[tt] = ~0;
1876     }
1877   }
1878
1879   am->fa_min_deleted_sessions_per_interval = ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
1880   am->fa_max_deleted_sessions_per_interval = ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
1881   am->fa_cleaner_wait_time_increment = ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
1882
1883   am->fa_cleaner_cnt_delete_by_sw_index = 0;
1884   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
1885   am->fa_cleaner_cnt_unknown_event = 0;
1886   am->fa_cleaner_cnt_deleted_sessions = 0;
1887   am->fa_cleaner_cnt_timer_restarted = 0;
1888   am->fa_cleaner_cnt_wait_with_timeout = 0;
1889
1890
1891 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
1892   foreach_acl_eh
1893 #undef _
1894
1895   am->l4_match_nonfirst_fragment = 1;
1896
1897   return error;
1898 }
1899
1900 VLIB_INIT_FUNCTION (acl_init);