ACL: Add coding-style-patch-verification and indent.
[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
29 /* define message IDs */
30 #include <acl/acl_msg_enum.h>
31
32 /* define message structures */
33 #define vl_typedefs
34 #include <acl/acl_all_api_h.h>
35 #undef vl_typedefs
36
37 /* define generated endian-swappers */
38 #define vl_endianfun
39 #include <acl/acl_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <acl/acl_all_api_h.h>
46 #undef vl_printfun
47
48 /* Get the API version number */
49 #define vl_api_version(n,v) static u32 api_version=(v);
50 #include <acl/acl_all_api_h.h>
51 #undef vl_api_version
52
53 #include "fa_node.h"
54 #include "hash_lookup.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_PLUGIN_CONTROL_PING, acl_plugin_control_ping) \
66 _(ACL_ADD_REPLACE, acl_add_replace)                             \
67 _(ACL_DEL, acl_del)                             \
68 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
69 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)       \
70 _(ACL_DUMP, acl_dump)  \
71 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
72 _(MACIP_ACL_ADD, macip_acl_add) \
73 _(MACIP_ACL_ADD_REPLACE, macip_acl_add_replace) \
74 _(MACIP_ACL_DEL, macip_acl_del) \
75 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
76 _(MACIP_ACL_DUMP, macip_acl_dump) \
77 _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) \
78 _(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump)
79
80
81 /* *INDENT-OFF* */
82 VLIB_PLUGIN_REGISTER () = {
83     .version = VPP_BUILD_VER,
84     .description = "Access Control Lists",
85 };
86 /* *INDENT-ON* */
87
88
89 static void *
90 acl_set_heap (acl_main_t * am)
91 {
92   if (0 == am->acl_mheap)
93     {
94       am->acl_mheap = mheap_alloc (0 /* use VM */ , am->acl_mheap_size);
95       mheap_t *h = mheap_header (am->acl_mheap);
96       h->flags |= MHEAP_FLAG_THREAD_SAFE;
97     }
98   void *oldheap = clib_mem_set_heap (am->acl_mheap);
99   return oldheap;
100 }
101
102 void
103 acl_plugin_acl_set_validate_heap (acl_main_t * am, int on)
104 {
105   clib_mem_set_heap (acl_set_heap (am));
106   mheap_t *h = mheap_header (am->acl_mheap);
107   if (on)
108     {
109       h->flags |= MHEAP_FLAG_VALIDATE;
110       h->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
111       mheap_validate (h);
112     }
113   else
114     {
115       h->flags &= ~MHEAP_FLAG_VALIDATE;
116       h->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
117     }
118 }
119
120 void
121 acl_plugin_acl_set_trace_heap (acl_main_t * am, int on)
122 {
123   clib_mem_set_heap (acl_set_heap (am));
124   mheap_t *h = mheap_header (am->acl_mheap);
125   if (on)
126     {
127       h->flags |= MHEAP_FLAG_TRACE;
128     }
129   else
130     {
131       h->flags &= ~MHEAP_FLAG_TRACE;
132     }
133 }
134
135 static void
136 vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
137 {
138   acl_main_t *am = &acl_main;
139   vl_api_acl_plugin_get_version_reply_t *rmp;
140   int msg_size = sizeof (*rmp);
141   unix_shared_memory_queue_t *q;
142
143   q = vl_api_client_index_to_input_queue (mp->client_index);
144   if (q == 0)
145     {
146       return;
147     }
148
149   rmp = vl_msg_api_alloc (msg_size);
150   memset (rmp, 0, msg_size);
151   rmp->_vl_msg_id =
152     ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
153   rmp->context = mp->context;
154   rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
155   rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
156
157   vl_msg_api_send_shmem (q, (u8 *) & rmp);
158 }
159
160 static void
161 vl_api_acl_plugin_control_ping_t_handler (vl_api_acl_plugin_control_ping_t *
162                                           mp)
163 {
164   vl_api_acl_plugin_control_ping_reply_t *rmp;
165   acl_main_t *am = &acl_main;
166   int rv = 0;
167
168   /* *INDENT-OFF* */
169   REPLY_MACRO2 (VL_API_ACL_PLUGIN_CONTROL_PING_REPLY,
170   ({
171     rmp->vpe_pid = ntohl (getpid ());
172   }));
173   /* *INDENT-ON* */
174 }
175
176 static int
177 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
178               u32 * acl_list_index, u8 * tag)
179 {
180   acl_main_t *am = &acl_main;
181   acl_list_t *a;
182   acl_rule_t *r;
183   acl_rule_t *acl_new_rules = 0;
184   int i;
185
186   if (*acl_list_index != ~0)
187     {
188       /* They supplied some number, let's see if this ACL exists */
189       if (pool_is_free_index (am->acls, *acl_list_index))
190         {
191           /* tried to replace a non-existent ACL, no point doing anything */
192           clib_warning
193             ("acl-plugin-error: Trying to replace nonexistent ACL %d (tag %s)",
194              *acl_list_index, tag);
195           return VNET_API_ERROR_NO_SUCH_ENTRY;
196         }
197     }
198   if (0 == count)
199     {
200       clib_warning
201         ("acl-plugin-warning: supplied no rules for ACL %d (tag %s)",
202          *acl_list_index, tag);
203     }
204
205   void *oldheap = acl_set_heap (am);
206
207   /* Create and populate the rules */
208   if (count > 0)
209     vec_validate (acl_new_rules, count - 1);
210
211   for (i = 0; i < count; i++)
212     {
213       r = vec_elt_at_index (acl_new_rules, i);
214       memset (r, 0, sizeof (*r));
215       r->is_permit = rules[i].is_permit;
216       r->is_ipv6 = rules[i].is_ipv6;
217       if (r->is_ipv6)
218         {
219           memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src));
220           memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst));
221         }
222       else
223         {
224           memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4));
225           memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4));
226         }
227       r->src_prefixlen = rules[i].src_ip_prefix_len;
228       r->dst_prefixlen = rules[i].dst_ip_prefix_len;
229       r->proto = rules[i].proto;
230       r->src_port_or_type_first = ntohs (rules[i].srcport_or_icmptype_first);
231       r->src_port_or_type_last = ntohs (rules[i].srcport_or_icmptype_last);
232       r->dst_port_or_code_first = ntohs (rules[i].dstport_or_icmpcode_first);
233       r->dst_port_or_code_last = ntohs (rules[i].dstport_or_icmpcode_last);
234       r->tcp_flags_value = rules[i].tcp_flags_value;
235       r->tcp_flags_mask = rules[i].tcp_flags_mask;
236     }
237
238   if (~0 == *acl_list_index)
239     {
240       /* Get ACL index */
241       pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
242       memset (a, 0, sizeof (*a));
243       /* Will return the newly allocated ACL index */
244       *acl_list_index = a - am->acls;
245     }
246   else
247     {
248       a = am->acls + *acl_list_index;
249       hash_acl_delete (am, *acl_list_index);
250       /* Get rid of the old rules */
251       if (a->rules)
252         vec_free (a->rules);
253     }
254   a->rules = acl_new_rules;
255   a->count = count;
256   memcpy (a->tag, tag, sizeof (a->tag));
257   hash_acl_add (am, *acl_list_index);
258   clib_mem_set_heap (oldheap);
259   return 0;
260 }
261
262 static int
263 acl_del_list (u32 acl_list_index)
264 {
265   acl_main_t *am = &acl_main;
266   acl_list_t *a;
267   int i, ii;
268   if (pool_is_free_index (am->acls, acl_list_index))
269     {
270       return VNET_API_ERROR_NO_SUCH_ENTRY;
271     }
272
273   if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
274     {
275       if (vec_len (vec_elt (am->input_sw_if_index_vec_by_acl, acl_list_index))
276           > 0)
277         {
278           /* ACL is applied somewhere inbound. Refuse to delete */
279           return VNET_API_ERROR_ACL_IN_USE_INBOUND;
280         }
281     }
282   if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
283     {
284       if (vec_len
285           (vec_elt (am->output_sw_if_index_vec_by_acl, acl_list_index)) > 0)
286         {
287           /* ACL is applied somewhere outbound. Refuse to delete */
288           return VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
289         }
290     }
291
292   void *oldheap = acl_set_heap (am);
293   /* delete any references to the ACL */
294   for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++)
295     {
296       for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]);
297            /* see body */ )
298         {
299           if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii])
300             {
301               vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii);
302             }
303           else
304             {
305               ii++;
306             }
307         }
308     }
309   for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++)
310     {
311       for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]);
312            /* see body */ )
313         {
314           if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii])
315             {
316               vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii);
317             }
318           else
319             {
320               ii++;
321             }
322         }
323     }
324   /* delete the hash table data */
325
326   hash_acl_delete (am, acl_list_index);
327   /* now we can delete the ACL itself */
328   a = pool_elt_at_index (am->acls, acl_list_index);
329   if (a->rules)
330     vec_free (a->rules);
331
332   pool_put (am->acls, a);
333   clib_mem_set_heap (oldheap);
334   return 0;
335 }
336
337 /* Some aids in ASCII graphing the content */
338 #define XX "\377"
339 #define __ "\000"
340 #define DOT1AD "\210\250"
341 #define DOT1Q "\201\00"
342 #define _(x)
343 #define v
344 /* *INDENT-OFF* */
345
346 u8 ip4_5tuple_mask[] =
347   _("             dmac               smac            etype ")
348   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
349   _("        v ihl totlen   ")
350   _(0x0000)
351   __ __ __ __
352   _("        ident fl+fo    ")
353   _(0x0004)
354   __ __ __ __
355   _("       ttl pr checksum ")
356   _(0x0008)
357   __ XX __ __
358   _("        src address    ")
359   _(0x000C)
360   XX XX XX XX
361   _("        dst address    ")
362   _(0x0010)
363   XX XX XX XX
364   _("L4 T/U  sport dport    ")
365   _(tcpudp)
366   XX XX XX XX
367   _(padpad)
368   __ __ __ __
369   _(padpad)
370   __ __ __ __
371   _(padeth)
372   __ __;
373
374  u8 ip6_5tuple_mask[] =
375   _("             dmac               smac            etype ")
376   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
377   _("        v  tc + flow ")
378   _(0x0000) __ __ __ __
379   _("        plen  nh hl  ")
380   _(0x0004) __ __ XX __
381   _("        src address  ")
382   _(0x0008) XX XX XX XX
383   _(0x000C) XX XX XX XX
384   _(0x0010) XX XX XX XX
385   _(0x0014) XX XX XX XX
386   _("        dst address  ")
387   _(0x0018) XX XX XX XX
388   _(0x001C) XX XX XX XX
389   _(0x0020) XX XX XX XX
390   _(0x0024) XX XX XX XX
391   _("L4T/U  sport dport   ")
392   _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
393
394  u8 dot1q_5tuple_mask[] =
395    _("             dmac               smac          dot1q         etype ")
396    _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v DOT1Q __ __ v XX XX v
397    _(padpad) __ __ __ __
398    _(padpad) __ __ __ __
399    _(padpad) __ __ __ __
400    _(padeth) __ __;
401
402  u8 dot1ad_5tuple_mask[] =
403    _("             dmac               smac          dot1ad                     etype ")
404    _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v DOT1AD __ __ DOT1Q __ __ v XX XX v
405    _(padpad) __ __ __ __
406    _(padpad) __ __ __ __
407    _(padeth) __ __;
408
409 /* *INDENT-ON* */
410 #undef XX
411 #undef __
412 #undef DOT1AD
413 #undef DOT1Q
414 #undef _
415 #undef v
416
417 static int
418 count_skip (u8 * p, u32 size)
419 {
420   u64 *p64 = (u64 *) p;
421   /* Be tolerant to null pointer */
422   if (0 == p)
423     return 0;
424
425   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
426     {
427       p64++;
428     }
429   return (p64 - (u64 *) p) / 2;
430 }
431
432 static int
433 acl_classify_add_del_table_tiny (vnet_classify_main_t * cm, u8 * mask,
434                                  u32 mask_len, u32 next_table_index,
435                                  u32 miss_next_index, u32 * table_index,
436                                  int is_add)
437 {
438   u32 nbuckets = 1;
439   u32 memory_size = 2 << 13;
440   u32 skip = count_skip (mask, mask_len);
441   u32 match = (mask_len / 16) - skip;
442   u8 *skip_mask_ptr = mask + 16 * skip;
443   u32 current_data_flag = 0;
444   int current_data_offset = 0;
445
446   if (0 == match)
447     match = 1;
448   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
449   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
450                                          memory_size, skip, match,
451                                          next_table_index, miss_next_index,
452                                          table_index, current_data_flag,
453                                          current_data_offset, is_add,
454                                          1 /* delete_chain */ );
455   clib_mem_set_heap (oldheap);
456   return ret;
457 }
458
459 static int
460 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
461                                   u32 mask_len, u32 next_table_index,
462                                   u32 miss_next_index, u32 * table_index,
463                                   int is_add)
464 {
465   u32 nbuckets = 32;
466   u32 memory_size = 2 << 22;
467   u32 skip = count_skip (mask, mask_len);
468   u32 match = (mask_len / 16) - skip;
469   u8 *skip_mask_ptr = mask + 16 * skip;
470   u32 current_data_flag = 0;
471   int current_data_offset = 0;
472
473   if (0 == match)
474     match = 1;
475
476   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
477   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
478                                          memory_size, skip, match,
479                                          next_table_index, miss_next_index,
480                                          table_index, current_data_flag,
481                                          current_data_offset, is_add,
482                                          1 /* delete_chain */ );
483   clib_mem_set_heap (oldheap);
484   return ret;
485 }
486
487 static int
488 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
489 {
490   vnet_classify_main_t *cm = &vnet_classify_main;
491   u32 ip4_table_index = ~0;
492   u32 ip6_table_index = ~0;
493   u32 dot1q_table_index = ~0;
494   u32 dot1ad_table_index = ~0;
495   void *oldheap = acl_set_heap (am);
496
497   vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
498                            sw_if_index, ~0);
499   vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
500                            sw_if_index, ~0);
501   vec_validate_init_empty (am->acl_dot1q_input_classify_table_by_sw_if_index,
502                            sw_if_index, ~0);
503   vec_validate_init_empty (am->acl_dot1ad_input_classify_table_by_sw_if_index,
504                            sw_if_index, ~0);
505
506   /* switch to global heap while calling vnet_* functions */
507   clib_mem_set_heap (cm->vlib_main->heap_base);
508   vnet_l2_input_classify_enable_disable (sw_if_index, 0);
509
510   if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
511     {
512       ip4_table_index =
513         am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
514       am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
515       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
516                                        sizeof (ip4_5tuple_mask) - 1, ~0,
517                                        am->l2_input_classify_next_acl_ip4,
518                                        &ip4_table_index, 0);
519     }
520   if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
521     {
522       ip6_table_index =
523         am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
524       am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
525       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
526                                        sizeof (ip6_5tuple_mask) - 1, ~0,
527                                        am->l2_input_classify_next_acl_ip6,
528                                        &ip6_table_index, 0);
529     }
530   if (am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
531     {
532       dot1q_table_index =
533         am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index];
534       am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
535       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
536                                        sizeof (ip6_5tuple_mask) - 1, ~0,
537                                        ~0, &dot1q_table_index, 0);
538     }
539   if (am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
540     {
541       dot1ad_table_index =
542         am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index];
543       am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
544       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
545                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
546                                        ~0, &dot1ad_table_index, 0);
547     }
548   clib_mem_set_heap (oldheap);
549   return 0;
550 }
551
552 static int
553 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
554 {
555   vnet_classify_main_t *cm = &vnet_classify_main;
556   u32 ip4_table_index = ~0;
557   u32 ip6_table_index = ~0;
558   u32 dot1q_table_index = ~0;
559   u32 dot1ad_table_index = ~0;
560   void *oldheap = acl_set_heap (am);
561
562   vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
563                            sw_if_index, ~0);
564   vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
565                            sw_if_index, ~0);
566   vec_validate_init_empty (am->acl_dot1q_output_classify_table_by_sw_if_index,
567                            sw_if_index, ~0);
568   vec_validate_init_empty
569     (am->acl_dot1ad_output_classify_table_by_sw_if_index, sw_if_index, ~0);
570
571   /* switch to global heap while calling vnet_* functions */
572   clib_mem_set_heap (cm->vlib_main->heap_base);
573
574   vnet_l2_output_classify_enable_disable (sw_if_index, 0);
575
576   if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
577     {
578       ip4_table_index =
579         am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
580       am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
581       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
582                                        sizeof (ip4_5tuple_mask) - 1, ~0,
583                                        am->l2_output_classify_next_acl_ip4,
584                                        &ip4_table_index, 0);
585     }
586   if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
587     {
588       ip6_table_index =
589         am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
590       am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
591       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
592                                        sizeof (ip6_5tuple_mask) - 1, ~0,
593                                        am->l2_output_classify_next_acl_ip6,
594                                        &ip6_table_index, 0);
595     }
596   if (am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
597     {
598       dot1q_table_index =
599         am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index];
600       am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
601       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
602                                        sizeof (ip6_5tuple_mask) - 1, ~0,
603                                        ~0, &dot1q_table_index, 0);
604     }
605   if (am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
606     {
607       dot1ad_table_index =
608         am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index];
609       am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
610       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
611                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
612                                        ~0, &dot1ad_table_index, 0);
613     }
614   clib_mem_set_heap (oldheap);
615   return 0;
616 }
617
618 static void
619 acl_add_vlan_session (acl_main_t * am, u32 table_index, u8 is_output,
620                       u8 is_dot1ad, u8 is_ip6)
621 {
622   vnet_classify_main_t *cm = &vnet_classify_main;
623   u8 *match;
624   u32 next_acl;
625   u8 idx;
626   u8 session_idx;
627
628   if (is_ip6)
629     {
630       next_acl =
631         (is_output) ? am->
632         l2_output_classify_next_acl_ip6 : am->l2_input_classify_next_acl_ip6;
633     }
634   else
635     {
636       next_acl =
637         (is_output) ? am->
638         l2_output_classify_next_acl_ip4 : am->l2_input_classify_next_acl_ip4;
639     }
640   match = (is_dot1ad) ? dot1ad_5tuple_mask : dot1q_5tuple_mask;
641   idx = (is_dot1ad) ? 20 : 16;
642
643   /* add sessions to vlan tables per ethernet_type */
644   if (is_ip6)
645     {
646       match[idx] = 0x86;
647       match[idx + 1] = 0xdd;
648       session_idx = 1;
649     }
650   else
651     {
652       match[idx] = 0x08;
653       match[idx + 1] = 0x00;
654       session_idx = 0;
655     }
656   vnet_classify_add_del_session (cm, table_index, match, next_acl,
657                                  session_idx, 0, 0, 0, 1);
658   memset (&match[idx], 0x00, 2);
659 }
660
661 static int
662 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
663 {
664   vnet_classify_main_t *cm = &vnet_classify_main;
665   u32 ip4_table_index = ~0;
666   u32 ip6_table_index = ~0;
667   u32 dot1q_table_index = ~0;
668   u32 dot1ad_table_index = ~0;
669   int rv;
670
671   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
672
673   /* in case there were previous tables attached */
674   acl_unhook_l2_input_classify (am, sw_if_index);
675   rv =
676     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
677                                      sizeof (ip4_5tuple_mask) - 1, ~0,
678                                      am->l2_input_classify_next_acl_ip4,
679                                      &ip4_table_index, 1);
680   if (rv)
681     goto done;
682
683   rv =
684     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
685                                      sizeof (ip6_5tuple_mask) - 1, ~0,
686                                      am->l2_input_classify_next_acl_ip6,
687                                      &ip6_table_index, 1);
688   if (rv)
689     {
690       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
691                                        sizeof (ip4_5tuple_mask) - 1, ~0,
692                                        am->l2_input_classify_next_acl_ip4,
693                                        &ip4_table_index, 0);
694       goto done;
695     }
696
697   rv =
698     acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
699                                      sizeof (dot1ad_5tuple_mask) - 1, ~0,
700                                      ~0, &dot1ad_table_index, 1);
701   rv =
702     acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
703                                      sizeof (dot1q_5tuple_mask) - 1,
704                                      dot1ad_table_index, ~0,
705                                      &dot1q_table_index, 1);
706   if (rv)
707     {
708       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
709                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
710                                        ~0, &dot1ad_table_index, 0);
711       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
712                                        sizeof (ip6_5tuple_mask) - 1, ~0,
713                                        am->l2_input_classify_next_acl_ip6,
714                                        &ip6_table_index, 0);
715       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
716                                        sizeof (ip4_5tuple_mask) - 1, ~0,
717                                        am->l2_input_classify_next_acl_ip4,
718                                        &ip4_table_index, 0);
719       goto done;
720     }
721
722   rv =
723     vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
724                                        ip6_table_index, dot1q_table_index);
725
726   if (rv)
727     {
728       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
729                                        sizeof (ip4_5tuple_mask) - 1, ~0,
730                                        am->l2_input_classify_next_acl_ip4,
731                                        &ip4_table_index, 0);
732       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
733                                        sizeof (ip6_5tuple_mask) - 1, ~0,
734                                        am->l2_input_classify_next_acl_ip6,
735                                        &ip6_table_index, 0);
736       acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
737                                        sizeof (dot1q_5tuple_mask) - 1, ~0,
738                                        ~0, &dot1q_table_index, 0);
739       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
740                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
741                                        ~0, &dot1ad_table_index, 0);
742       goto done;
743     }
744
745   /* add sessions to vlan tables per ethernet_type */
746   acl_add_vlan_session (am, dot1q_table_index, 0, 0, 0);
747   acl_add_vlan_session (am, dot1q_table_index, 0, 0, 1);
748   acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 0);
749   acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 1);
750
751   am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
752     ip4_table_index;
753   am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
754     ip6_table_index;
755   am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] =
756     dot1q_table_index;
757   am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] =
758     dot1ad_table_index;
759
760   vnet_l2_input_classify_enable_disable (sw_if_index, 1);
761 done:
762   clib_mem_set_heap (prevheap);
763   return rv;
764 }
765
766 static int
767 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
768 {
769   vnet_classify_main_t *cm = &vnet_classify_main;
770   u32 ip4_table_index = ~0;
771   u32 ip6_table_index = ~0;
772   u32 dot1q_table_index = ~0;
773   u32 dot1ad_table_index = ~0;
774   int rv;
775
776   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
777
778   /* in case there were previous tables attached */
779   acl_unhook_l2_output_classify (am, sw_if_index);
780   rv =
781     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
782                                      sizeof (ip4_5tuple_mask) - 1, ~0,
783                                      am->l2_output_classify_next_acl_ip4,
784                                      &ip4_table_index, 1);
785   if (rv)
786     goto done;
787   rv =
788     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
789                                      sizeof (ip6_5tuple_mask) - 1, ~0,
790                                      am->l2_output_classify_next_acl_ip6,
791                                      &ip6_table_index, 1);
792   if (rv)
793     {
794       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
795                                        sizeof (ip4_5tuple_mask) - 1, ~0,
796                                        am->l2_output_classify_next_acl_ip4,
797                                        &ip4_table_index, 0);
798       goto done;
799     }
800
801   rv =
802     acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
803                                      sizeof (dot1ad_5tuple_mask) - 1, ~0,
804                                      ~0, &dot1ad_table_index, 1);
805   rv =
806     acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
807                                      sizeof (dot1q_5tuple_mask) - 1,
808                                      dot1ad_table_index, ~0,
809                                      &dot1q_table_index, 1);
810   if (rv)
811     {
812       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
813                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
814                                        ~0, &dot1ad_table_index, 0);
815       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
816                                        sizeof (ip6_5tuple_mask) - 1, ~0,
817                                        am->l2_output_classify_next_acl_ip6,
818                                        &ip6_table_index, 0);
819       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
820                                        sizeof (ip4_5tuple_mask) - 1, ~0,
821                                        am->l2_output_classify_next_acl_ip4,
822                                        &ip4_table_index, 0);
823       goto done;
824     }
825
826   rv =
827     vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
828                                         ip6_table_index, dot1q_table_index);
829
830   clib_warning
831     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
832      sw_if_index, ip4_table_index, ip6_table_index);
833   if (rv)
834     {
835       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
836                                        sizeof (ip6_5tuple_mask) - 1, ~0,
837                                        am->l2_output_classify_next_acl_ip6,
838                                        &ip6_table_index, 0);
839       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
840                                        sizeof (ip4_5tuple_mask) - 1, ~0,
841                                        am->l2_output_classify_next_acl_ip4,
842                                        &ip4_table_index, 0);
843       acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
844                                        sizeof (dot1q_5tuple_mask) - 1, ~0,
845                                        ~0, &dot1q_table_index, 0);
846       acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
847                                        sizeof (dot1ad_5tuple_mask) - 1, ~0,
848                                        ~0, &dot1ad_table_index, 0);
849       goto done;
850     }
851
852   /* add sessions to vlan tables per ethernet_type */
853   acl_add_vlan_session (am, dot1q_table_index, 1, 0, 0);
854   acl_add_vlan_session (am, dot1q_table_index, 1, 0, 1);
855   acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 0);
856   acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 1);
857
858   am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
859     ip4_table_index;
860   am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
861     ip6_table_index;
862   am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] =
863     dot1q_table_index;
864   am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] =
865     dot1ad_table_index;
866
867   vnet_l2_output_classify_enable_disable (sw_if_index, 1);
868 done:
869   clib_mem_set_heap (prevheap);
870   return rv;
871 }
872
873 int
874 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
875                                  int enable_disable)
876 {
877   int rv;
878
879   /* Utterly wrong? */
880   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
881                           sw_if_index))
882     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
883
884   acl_fa_enable_disable (sw_if_index, 1, enable_disable);
885
886   if (enable_disable)
887     {
888       rv = acl_hook_l2_input_classify (am, sw_if_index);
889     }
890   else
891     {
892       rv = acl_unhook_l2_input_classify (am, sw_if_index);
893     }
894
895   return rv;
896 }
897
898 int
899 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
900                                   int enable_disable)
901 {
902   int rv;
903
904   /* Utterly wrong? */
905   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
906                           sw_if_index))
907     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
908
909   acl_fa_enable_disable (sw_if_index, 0, enable_disable);
910
911   if (enable_disable)
912     {
913       rv = acl_hook_l2_output_classify (am, sw_if_index);
914     }
915   else
916     {
917       rv = acl_unhook_l2_output_classify (am, sw_if_index);
918     }
919
920   return rv;
921 }
922
923 static int
924 acl_is_not_defined (acl_main_t * am, u32 acl_list_index)
925 {
926   return (pool_is_free_index (am->acls, acl_list_index));
927 }
928
929
930 static int
931 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
932 {
933   acl_main_t *am = &acl_main;
934   if (acl_is_not_defined (am, acl_list_index))
935     {
936       /* ACL is not defined. Can not apply */
937       return VNET_API_ERROR_NO_SUCH_ENTRY;
938     }
939   void *oldheap = acl_set_heap (am);
940
941   if (is_input)
942     {
943       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
944
945       u32 index = vec_search (am->input_acl_vec_by_sw_if_index[sw_if_index],
946                               acl_list_index);
947       if (index < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
948         {
949           clib_warning
950             ("ACL %d is already applied inbound on sw_if_index %d (index %d)",
951              acl_list_index, sw_if_index, index);
952           /* the entry is already there */
953           clib_mem_set_heap (oldheap);
954           return VNET_API_ERROR_ACL_IN_USE_INBOUND;
955         }
956       /* if there was no ACL applied before, enable the ACL processing */
957       if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) == 0)
958         {
959           acl_interface_in_enable_disable (am, sw_if_index, 1);
960         }
961       vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
962                1);
963       vec_validate (am->input_sw_if_index_vec_by_acl, acl_list_index);
964       vec_add (am->input_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
965                1);
966     }
967   else
968     {
969       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
970
971       u32 index = vec_search (am->output_acl_vec_by_sw_if_index[sw_if_index],
972                               acl_list_index);
973       if (index < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
974         {
975           clib_warning
976             ("ACL %d is already applied outbound on sw_if_index %d (index %d)",
977              acl_list_index, sw_if_index, index);
978           /* the entry is already there */
979           clib_mem_set_heap (oldheap);
980           return VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
981         }
982       /* if there was no ACL applied before, enable the ACL processing */
983       if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) == 0)
984         {
985           acl_interface_out_enable_disable (am, sw_if_index, 1);
986         }
987       vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
988                &acl_list_index, 1);
989       vec_validate (am->output_sw_if_index_vec_by_acl, acl_list_index);
990       vec_add (am->output_sw_if_index_vec_by_acl[acl_list_index],
991                &sw_if_index, 1);
992     }
993   clib_mem_set_heap (oldheap);
994   return 0;
995 }
996
997
998 static int
999 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
1000 {
1001   acl_main_t *am = &acl_main;
1002   int i;
1003   int rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1004   void *oldheap = acl_set_heap (am);
1005   if (is_input)
1006     {
1007       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1008       for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1009            i++)
1010         {
1011           if (acl_list_index ==
1012               am->input_acl_vec_by_sw_if_index[sw_if_index][i])
1013             {
1014               vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
1015               rv = 0;
1016               break;
1017             }
1018         }
1019
1020       if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
1021         {
1022           u32 index =
1023             vec_search (am->input_sw_if_index_vec_by_acl[acl_list_index],
1024                         sw_if_index);
1025           if (index <
1026               vec_len (am->input_sw_if_index_vec_by_acl[acl_list_index]))
1027             {
1028               hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1029               vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index],
1030                         index);
1031             }
1032         }
1033
1034       /* If there is no more ACLs applied on an interface, disable ACL processing */
1035       if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
1036         {
1037           acl_interface_in_enable_disable (am, sw_if_index, 0);
1038         }
1039     }
1040   else
1041     {
1042       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1043       for (i = 0;
1044            i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
1045         {
1046           if (acl_list_index ==
1047               am->output_acl_vec_by_sw_if_index[sw_if_index][i])
1048             {
1049               vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
1050               rv = 0;
1051               break;
1052             }
1053         }
1054
1055       if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
1056         {
1057           u32 index =
1058             vec_search (am->output_sw_if_index_vec_by_acl[acl_list_index],
1059                         sw_if_index);
1060           if (index <
1061               vec_len (am->output_sw_if_index_vec_by_acl[acl_list_index]))
1062             {
1063               hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1064               vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index],
1065                         index);
1066             }
1067         }
1068
1069       /* If there is no more ACLs applied on an interface, disable ACL processing */
1070       if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
1071         {
1072           acl_interface_out_enable_disable (am, sw_if_index, 0);
1073         }
1074     }
1075   clib_mem_set_heap (oldheap);
1076   return rv;
1077 }
1078
1079 static void
1080 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
1081 {
1082   acl_main_t *am = &acl_main;
1083   int i;
1084   void *oldheap = acl_set_heap (am);
1085   if (is_input)
1086     {
1087       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1088       if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1089         {
1090           acl_interface_in_enable_disable (am, sw_if_index, 0);
1091         }
1092
1093       for (i = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) - 1;
1094            i >= 0; i--)
1095         {
1096           u32 acl_list_index =
1097             am->input_acl_vec_by_sw_if_index[sw_if_index][i];
1098           hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1099           if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
1100             {
1101               u32 index =
1102                 vec_search (am->input_sw_if_index_vec_by_acl[acl_list_index],
1103                             sw_if_index);
1104               if (index <
1105                   vec_len (am->input_sw_if_index_vec_by_acl[acl_list_index]))
1106                 {
1107                   vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index],
1108                             index);
1109                 }
1110             }
1111         }
1112
1113       vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1114     }
1115   else
1116     {
1117       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1118       if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1119         {
1120           acl_interface_out_enable_disable (am, sw_if_index, 0);
1121         }
1122
1123       for (i = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) - 1;
1124            i >= 0; i--)
1125         {
1126           u32 acl_list_index =
1127             am->output_acl_vec_by_sw_if_index[sw_if_index][i];
1128           hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1129           if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
1130             {
1131               u32 index =
1132                 vec_search (am->output_sw_if_index_vec_by_acl[acl_list_index],
1133                             sw_if_index);
1134               if (index <
1135                   vec_len (am->output_sw_if_index_vec_by_acl[acl_list_index]))
1136                 {
1137                   vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index],
1138                             index);
1139                 }
1140             }
1141         }
1142
1143       vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1144     }
1145   clib_mem_set_heap (oldheap);
1146 }
1147
1148 static int
1149 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
1150                                  u32 acl_list_index)
1151 {
1152   int rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1153   acl_main_t *am = &acl_main;
1154   if (is_add)
1155     {
1156       rv =
1157         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
1158       if (rv == 0)
1159         {
1160           hash_acl_apply (am, sw_if_index, is_input, acl_list_index);
1161         }
1162     }
1163   else
1164     {
1165       hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1166       rv =
1167         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
1168     }
1169   return rv;
1170 }
1171
1172
1173 typedef struct
1174 {
1175   u8 is_ipv6;
1176   u8 mac_mask[6];
1177   u8 prefix_len;
1178   u32 count;
1179   u32 table_index;
1180   u32 arp_table_index;
1181   u32 dot1q_table_index;
1182   u32 dot1ad_table_index;
1183 } macip_match_type_t;
1184
1185 static u32
1186 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
1187                        u8 is_ipv6)
1188 {
1189   u32 i;
1190   if (mv)
1191     {
1192       for (i = 0; i < vec_len (mv); i++)
1193         {
1194           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
1195               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
1196             {
1197               return i;
1198             }
1199         }
1200     }
1201   return ~0;
1202 }
1203
1204
1205 /* Get metric used to sort match types.
1206    The more specific and the more often seen - the bigger the metric */
1207 static int
1208 match_type_metric (macip_match_type_t * m)
1209 {
1210   unsigned int mac_bits_set = 0;
1211   unsigned int mac_byte;
1212   int i;
1213   for (i = 0; i < 6; i++)
1214     {
1215       mac_byte = m->mac_mask[i];
1216       for (; mac_byte; mac_byte >>= 1)
1217         mac_bits_set += mac_byte & 1;
1218     }
1219   /*
1220    * Attempt to place the more specific and the more used rules on top.
1221    * There are obvious caveat corner cases to this, but they do not
1222    * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
1223    * going with a wildcard IPv4 with a specific MAC).
1224    */
1225   return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
1226 }
1227
1228 static int
1229 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
1230 {
1231   /* Ascending sort based on the metric values */
1232   return match_type_metric (m1) - match_type_metric (m2);
1233 }
1234
1235 /* Get the offset of L3 source within ethernet packet */
1236 static int
1237 get_l3_src_offset (int is6)
1238 {
1239   if (is6)
1240     return (sizeof (ethernet_header_t) +
1241             offsetof (ip6_header_t, src_address));
1242   else
1243     return (sizeof (ethernet_header_t) +
1244             offsetof (ip4_header_t, src_address));
1245 }
1246
1247 static int
1248 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
1249 {
1250   macip_match_type_t *mvec = NULL;
1251   macip_match_type_t *mt;
1252   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1253   int i;
1254   u32 match_type_index;
1255   u32 last_table;
1256   u8 mask[5 * 16];
1257   vnet_classify_main_t *cm = &vnet_classify_main;
1258
1259   /* Count the number of different types of rules */
1260   for (i = 0; i < a->count; i++)
1261     {
1262       if (~0 ==
1263           (match_type_index =
1264            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1265                                   a->rules[i].src_prefixlen,
1266                                   a->rules[i].is_ipv6)))
1267         {
1268           match_type_index = vec_len (mvec);
1269           vec_validate (mvec, match_type_index);
1270           memcpy (mvec[match_type_index].mac_mask,
1271                   a->rules[i].src_mac_mask, 6);
1272           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1273           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1274           mvec[match_type_index].table_index = ~0;
1275           mvec[match_type_index].dot1q_table_index = ~0;
1276           mvec[match_type_index].dot1ad_table_index = ~0;
1277         }
1278       mvec[match_type_index].count++;
1279     }
1280   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1281   vec_sort_with_function (mvec, match_type_compare);
1282   /* Create the classifier tables */
1283   last_table = ~0;
1284   /* First add ARP tables */
1285   vec_foreach (mt, mvec)
1286   {
1287     int mask_len;
1288     int is6 = mt->is_ipv6;
1289
1290     mt->arp_table_index = ~0;
1291     if (!is6)
1292       {
1293         memset (mask, 0, sizeof (mask));
1294         memcpy (&mask[6], mt->mac_mask, 6);
1295         memset (&mask[12], 0xff, 2);    /* ethernet protocol */
1296         memcpy (&mask[14 + 8], mt->mac_mask, 6);
1297
1298         for (i = 0; i < (mt->prefix_len / 8); i++)
1299           mask[14 + 14 + i] = 0xff;
1300         if (mt->prefix_len % 8)
1301           mask[14 + 14 + (mt->prefix_len / 8)] =
1302             0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1303
1304         mask_len = ((14 + 14 + ((mt->prefix_len + 7) / 8) +
1305                      (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
1306         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1307                                           (~0 == last_table) ? 0 : ~0,
1308                                           &mt->arp_table_index, 1);
1309         last_table = mt->arp_table_index;
1310       }
1311   }
1312   /* Now add IP[46] tables */
1313   vec_foreach (mt, mvec)
1314   {
1315     int mask_len;
1316     int is6 = mt->is_ipv6;
1317     int l3_src_offs = get_l3_src_offset (is6);
1318     int tags;
1319     u32 *last_tag_table;
1320
1321     /*
1322      * create chained tables for VLAN (no-tags, dot1q and dot1ad) packets
1323      */
1324     l3_src_offs += 8;
1325     for (tags = 2; tags >= 0; tags--)
1326       {
1327         memset (mask, 0, sizeof (mask));
1328         memcpy (&mask[6], mt->mac_mask, 6);
1329         switch (tags)
1330           {
1331           case 0:
1332           default:
1333             memset (&mask[12], 0xff, 2);        /* ethernet protocol */
1334             last_tag_table = &mt->table_index;
1335             break;
1336           case 1:
1337             memset (&mask[12], 0xff, 2);        /* VLAN tag1 */
1338             memset (&mask[16], 0xff, 2);        /* ethernet protocol */
1339             last_tag_table = &mt->dot1q_table_index;
1340             break;
1341           case 2:
1342             memset (&mask[12], 0xff, 2);        /* VLAN tag1 */
1343             memset (&mask[16], 0xff, 2);        /* VLAN tag2 */
1344             memset (&mask[20], 0xff, 2);        /* ethernet protocol */
1345             last_tag_table = &mt->dot1ad_table_index;
1346             break;
1347           }
1348         for (i = 0; i < (mt->prefix_len / 8); i++)
1349           {
1350             mask[l3_src_offs + i] = 0xff;
1351           }
1352         if (mt->prefix_len % 8)
1353           {
1354             mask[l3_src_offs + (mt->prefix_len / 8)] =
1355               0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1356           }
1357         /*
1358          * Round-up the number of bytes needed to store the prefix,
1359          * and round up the number of vectors too
1360          */
1361         mask_len = ((l3_src_offs + ((mt->prefix_len + 7) / 8) +
1362                      (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
1363         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1364                                           (~0 == last_table) ? 0 : ~0,
1365                                           last_tag_table, 1);
1366         last_table = *last_tag_table;
1367
1368         memset (&mask[12], 0, sizeof (mask) - 12);
1369         l3_src_offs -= 4;
1370       }
1371   }
1372   a->ip4_table_index = last_table;
1373   a->ip6_table_index = last_table;
1374   a->l2_table_index = last_table;
1375
1376   /* Populate the classifier tables with rules from the MACIP ACL */
1377   for (i = 0; i < a->count; i++)
1378     {
1379       u32 action = 0;
1380       u32 metadata = 0;
1381       int is6 = a->rules[i].is_ipv6;
1382       int l3_src_offs = get_l3_src_offset (is6);
1383       u32 tag_table;
1384       int tags, eth;
1385
1386       match_type_index =
1387         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1388                                a->rules[i].src_prefixlen,
1389                                a->rules[i].is_ipv6);
1390       ASSERT (match_type_index != ~0);
1391
1392       l3_src_offs += 8;
1393       for (tags = 2; tags >= 0; tags--)
1394         {
1395           memset (mask, 0, sizeof (mask));
1396           memcpy (&mask[6], a->rules[i].src_mac, 6);
1397           switch (tags)
1398             {
1399             case 0:
1400             default:
1401               tag_table = mvec[match_type_index].table_index;
1402               eth = 12;
1403               break;
1404             case 1:
1405               tag_table = mvec[match_type_index].dot1q_table_index;
1406               mask[12] = 0x81;
1407               mask[13] = 0x00;
1408               eth = 16;
1409               break;
1410             case 2:
1411               tag_table = mvec[match_type_index].dot1ad_table_index;
1412               mask[12] = 0x88;
1413               mask[13] = 0xa8;
1414               mask[16] = 0x81;
1415               mask[17] = 0x00;
1416               eth = 20;
1417               break;
1418             }
1419           if (is6)
1420             {
1421               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1422               mask[eth] = 0x86;
1423               mask[eth + 1] = 0xdd;
1424             }
1425           else
1426             {
1427               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1428               mask[eth] = 0x08;
1429               mask[eth + 1] = 0x00;
1430             }
1431
1432           /* add session to table mvec[match_type_index].table_index; */
1433           vnet_classify_add_del_session (cm, tag_table,
1434                                          mask, a->rules[i].is_permit ? ~0 : 0,
1435                                          i, 0, action, metadata, 1);
1436           memset (&mask[12], 0, sizeof (mask) - 12);
1437           l3_src_offs -= 4;
1438         }
1439
1440       /* add ARP table entry too */
1441       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1442         {
1443           memset (mask, 0, sizeof (mask));
1444           memcpy (&mask[6], a->rules[i].src_mac, 6);
1445           mask[12] = 0x08;
1446           mask[13] = 0x06;
1447           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
1448           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
1449           vnet_classify_add_del_session (cm,
1450                                          mvec
1451                                          [match_type_index].arp_table_index,
1452                                          mask, a->rules[i].is_permit ? ~0 : 0,
1453                                          i, 0, action, metadata, 1);
1454         }
1455     }
1456   return 0;
1457 }
1458
1459 static void
1460 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1461 {
1462   vnet_classify_main_t *cm = &vnet_classify_main;
1463   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1464
1465   if (a->ip4_table_index != ~0)
1466     {
1467       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1468                                         &a->ip4_table_index, 0);
1469       a->ip4_table_index = ~0;
1470     }
1471   if (a->ip6_table_index != ~0)
1472     {
1473       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1474                                         &a->ip6_table_index, 0);
1475       a->ip6_table_index = ~0;
1476     }
1477   if (a->l2_table_index != ~0)
1478     {
1479       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index,
1480                                         0);
1481       a->l2_table_index = ~0;
1482     }
1483 }
1484
1485 static int
1486 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1487                     u32 * acl_list_index, u8 * tag)
1488 {
1489   acl_main_t *am = &acl_main;
1490   macip_acl_list_t *a;
1491   macip_acl_rule_t *r;
1492   macip_acl_rule_t *acl_new_rules = 0;
1493   int i;
1494
1495   if (*acl_list_index != ~0)
1496     {
1497       /* They supplied some number, let's see if this MACIP ACL exists */
1498       if (pool_is_free_index (am->macip_acls, *acl_list_index))
1499         {
1500           /* tried to replace a non-existent ACL, no point doing anything */
1501           clib_warning
1502             ("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)",
1503              *acl_list_index, tag);
1504           return VNET_API_ERROR_NO_SUCH_ENTRY;
1505         }
1506     }
1507
1508   if (0 == count)
1509     {
1510       clib_warning
1511         ("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)",
1512          tag);
1513     }
1514   void *oldheap = acl_set_heap (am);
1515   /* Create and populate the rules */
1516   if (count > 0)
1517     vec_validate (acl_new_rules, count - 1);
1518
1519   for (i = 0; i < count; i++)
1520     {
1521       r = &acl_new_rules[i];
1522       r->is_permit = rules[i].is_permit;
1523       r->is_ipv6 = rules[i].is_ipv6;
1524       memcpy (&r->src_mac, rules[i].src_mac, 6);
1525       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1526       if (rules[i].is_ipv6)
1527         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1528       else
1529         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1530       r->src_prefixlen = rules[i].src_ip_prefix_len;
1531     }
1532
1533   if (~0 == *acl_list_index)
1534     {
1535       /* Get ACL index */
1536       pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1537       memset (a, 0, sizeof (*a));
1538       /* Will return the newly allocated ACL index */
1539       *acl_list_index = a - am->macip_acls;
1540     }
1541   else
1542     {
1543       a = pool_elt_at_index (am->macip_acls, *acl_list_index);
1544       if (a->rules)
1545         {
1546           vec_free (a->rules);
1547         }
1548       macip_destroy_classify_tables (am, *acl_list_index);
1549     }
1550
1551   a->rules = acl_new_rules;
1552   a->count = count;
1553   memcpy (a->tag, tag, sizeof (a->tag));
1554
1555   /* Create and populate the classifer tables */
1556   macip_create_classify_tables (am, *acl_list_index);
1557   clib_mem_set_heap (oldheap);
1558   return 0;
1559 }
1560
1561
1562 /* No check for validity of sw_if_index - the callers were supposed to validate */
1563
1564 static int
1565 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1566 {
1567   int rv;
1568   u32 macip_acl_index;
1569   macip_acl_list_t *a;
1570   void *oldheap = acl_set_heap (am);
1571   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1572   clib_mem_set_heap (oldheap);
1573   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1574   /* No point in deleting MACIP ACL which is not applied */
1575   if (~0 == macip_acl_index)
1576     return VNET_API_ERROR_NO_SUCH_ENTRY;
1577   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1578   /* remove the classifier tables off the interface L2 ACL */
1579   rv =
1580     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1581                               a->ip6_table_index, a->l2_table_index, 0);
1582   /* Unset the MACIP ACL index */
1583   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1584   return rv;
1585 }
1586
1587 /* No check for validity of sw_if_index - the callers were supposed to validate */
1588
1589 static int
1590 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1591                              u32 macip_acl_index)
1592 {
1593   macip_acl_list_t *a;
1594   int rv;
1595   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1596     {
1597       return VNET_API_ERROR_NO_SUCH_ENTRY;
1598     }
1599   void *oldheap = acl_set_heap (am);
1600   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1601   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1602   clib_mem_set_heap (oldheap);
1603   /* If there already a MACIP ACL applied, unapply it */
1604   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1605     macip_acl_interface_del_acl (am, sw_if_index);
1606   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1607
1608   /* Apply the classifier tables for L2 ACLs */
1609   rv =
1610     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1611                               a->ip6_table_index, a->l2_table_index, 1);
1612   return rv;
1613 }
1614
1615 static int
1616 macip_acl_del_list (u32 acl_list_index)
1617 {
1618   acl_main_t *am = &acl_main;
1619   macip_acl_list_t *a;
1620   int i;
1621   if (pool_is_free_index (am->macip_acls, acl_list_index))
1622     {
1623       return VNET_API_ERROR_NO_SUCH_ENTRY;
1624     }
1625
1626   /* delete any references to the ACL */
1627   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1628     {
1629       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1630         {
1631           macip_acl_interface_del_acl (am, i);
1632         }
1633     }
1634
1635   void *oldheap = acl_set_heap (am);
1636   /* Now that classifier tables are detached, clean them up */
1637   macip_destroy_classify_tables (am, acl_list_index);
1638
1639   /* now we can delete the ACL itself */
1640   a = pool_elt_at_index (am->macip_acls, acl_list_index);
1641   if (a->rules)
1642     {
1643       vec_free (a->rules);
1644     }
1645   pool_put (am->macip_acls, a);
1646   clib_mem_set_heap (oldheap);
1647   return 0;
1648 }
1649
1650
1651 static int
1652 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1653                                  u32 acl_list_index)
1654 {
1655   acl_main_t *am = &acl_main;
1656   int rv = -1;
1657   if (is_add)
1658     {
1659       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1660     }
1661   else
1662     {
1663       rv = macip_acl_interface_del_acl (am, sw_if_index);
1664     }
1665   return rv;
1666 }
1667
1668 /*
1669  * If the client does not allocate enough memory for a variable-length
1670  * message, and then proceed to use it as if the full memory allocated,
1671  * absent the check we happily consume that on the VPP side, and go
1672  * along as if nothing happened. However, the resulting
1673  * effects range from just garbage in the API decode
1674  * (because the decoder snoops too far), to potential memory
1675  * corruptions.
1676  *
1677  * This verifies that the actual length of the message is
1678  * at least expected_len, and complains loudly if it is not.
1679  *
1680  * A failing check here is 100% a software bug on the API user side,
1681  * so we might as well yell.
1682  *
1683  */
1684 static int
1685 verify_message_len (void *mp, u32 expected_len, char *where)
1686 {
1687   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1688   if (supplied_len < expected_len)
1689     {
1690       clib_warning ("%s: Supplied message length %d is less than expected %d",
1691                     where, supplied_len, expected_len);
1692       return 0;
1693     }
1694   else
1695     {
1696       return 1;
1697     }
1698 }
1699
1700 /* API message handler */
1701 static void
1702 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1703 {
1704   vl_api_acl_add_replace_reply_t *rmp;
1705   acl_main_t *am = &acl_main;
1706   int rv;
1707   u32 acl_list_index = ntohl (mp->acl_index);
1708   u32 acl_count = ntohl (mp->count);
1709   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
1710
1711   if (verify_message_len (mp, expected_len, "acl_add_replace"))
1712     {
1713       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1714     }
1715   else
1716     {
1717       rv = VNET_API_ERROR_INVALID_VALUE;
1718     }
1719
1720   /* *INDENT-OFF* */
1721   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1722   ({
1723     rmp->acl_index = htonl(acl_list_index);
1724   }));
1725   /* *INDENT-ON* */
1726 }
1727
1728 static void
1729 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1730 {
1731   acl_main_t *am = &acl_main;
1732   vl_api_acl_del_reply_t *rmp;
1733   int rv;
1734
1735   rv = acl_del_list (ntohl (mp->acl_index));
1736
1737   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1738 }
1739
1740 static void
1741 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1742 {
1743   acl_main_t *am = &acl_main;
1744   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1745   u32 sw_if_index = ntohl (mp->sw_if_index);
1746   vl_api_acl_interface_add_del_reply_t *rmp;
1747   int rv = -1;
1748
1749   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
1750     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1751   else
1752     rv =
1753       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1754                                        mp->is_input, ntohl (mp->acl_index));
1755
1756   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1757 }
1758
1759 static void
1760   vl_api_acl_interface_set_acl_list_t_handler
1761   (vl_api_acl_interface_set_acl_list_t * mp)
1762 {
1763   acl_main_t *am = &acl_main;
1764   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1765   int rv = 0;
1766   int i;
1767   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1768   u32 sw_if_index = ntohl (mp->sw_if_index);
1769
1770   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
1771     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1772   else
1773     {
1774       acl_interface_reset_inout_acls (sw_if_index, 0);
1775       acl_interface_reset_inout_acls (sw_if_index, 1);
1776
1777       for (i = 0; i < mp->count; i++)
1778         {
1779           if (acl_is_not_defined (am, ntohl (mp->acls[i])))
1780             {
1781               /* ACL does not exist, so we can not apply it */
1782               rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1783             }
1784         }
1785       if (0 == rv)
1786         {
1787           for (i = 0; i < mp->count; i++)
1788             {
1789               acl_interface_add_del_inout_acl (sw_if_index, 1,
1790                                                (i < mp->n_input),
1791                                                ntohl (mp->acls[i]));
1792             }
1793         }
1794     }
1795
1796   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1797 }
1798
1799 static void
1800 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1801 {
1802   api_rule->is_permit = r->is_permit;
1803   api_rule->is_ipv6 = r->is_ipv6;
1804   if (r->is_ipv6)
1805     {
1806       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1807       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1808     }
1809   else
1810     {
1811       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1812       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1813     }
1814   api_rule->src_ip_prefix_len = r->src_prefixlen;
1815   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1816   api_rule->proto = r->proto;
1817   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1818   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1819   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1820   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1821   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1822   api_rule->tcp_flags_value = r->tcp_flags_value;
1823 }
1824
1825 static void
1826 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1827                   acl_list_t * acl, u32 context)
1828 {
1829   vl_api_acl_details_t *mp;
1830   vl_api_acl_rule_t *rules;
1831   int i;
1832   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1833   void *oldheap = acl_set_heap (am);
1834
1835   mp = vl_msg_api_alloc (msg_size);
1836   memset (mp, 0, msg_size);
1837   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1838
1839   /* fill in the message */
1840   mp->context = context;
1841   mp->count = htonl (acl->count);
1842   mp->acl_index = htonl (acl - am->acls);
1843   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1844   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1845   rules = mp->r;
1846   for (i = 0; i < acl->count; i++)
1847     {
1848       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1849     }
1850
1851   clib_mem_set_heap (oldheap);
1852   vl_msg_api_send_shmem (q, (u8 *) & mp);
1853 }
1854
1855
1856 static void
1857 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1858 {
1859   acl_main_t *am = &acl_main;
1860   u32 acl_index;
1861   acl_list_t *acl;
1862
1863   int rv = -1;
1864   unix_shared_memory_queue_t *q;
1865
1866   q = vl_api_client_index_to_input_queue (mp->client_index);
1867   if (q == 0)
1868     {
1869       return;
1870     }
1871
1872   if (mp->acl_index == ~0)
1873     {
1874     /* *INDENT-OFF* */
1875     /* Just dump all ACLs */
1876     pool_foreach (acl, am->acls,
1877     ({
1878       send_acl_details(am, q, acl, mp->context);
1879     }));
1880     /* *INDENT-ON* */
1881     }
1882   else
1883     {
1884       acl_index = ntohl (mp->acl_index);
1885       if (!pool_is_free_index (am->acls, acl_index))
1886         {
1887           acl = pool_elt_at_index (am->acls, acl_index);
1888           send_acl_details (am, q, acl, mp->context);
1889         }
1890     }
1891
1892   if (rv == -1)
1893     {
1894       /* FIXME API: should we signal an error here at all ? */
1895       return;
1896     }
1897 }
1898
1899 static void
1900 send_acl_interface_list_details (acl_main_t * am,
1901                                  unix_shared_memory_queue_t * q,
1902                                  u32 sw_if_index, u32 context)
1903 {
1904   vl_api_acl_interface_list_details_t *mp;
1905   int msg_size;
1906   int n_input;
1907   int n_output;
1908   int count;
1909   int i = 0;
1910   void *oldheap = acl_set_heap (am);
1911
1912   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1913   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1914
1915   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1916   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1917   count = n_input + n_output;
1918
1919   msg_size = sizeof (*mp);
1920   msg_size += sizeof (mp->acls[0]) * count;
1921
1922   mp = vl_msg_api_alloc (msg_size);
1923   memset (mp, 0, msg_size);
1924   mp->_vl_msg_id =
1925     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1926
1927   /* fill in the message */
1928   mp->context = context;
1929   mp->sw_if_index = htonl (sw_if_index);
1930   mp->count = count;
1931   mp->n_input = n_input;
1932   for (i = 0; i < n_input; i++)
1933     {
1934       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1935     }
1936   for (i = 0; i < n_output; i++)
1937     {
1938       mp->acls[n_input + i] =
1939         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1940     }
1941   clib_mem_set_heap (oldheap);
1942   vl_msg_api_send_shmem (q, (u8 *) & mp);
1943 }
1944
1945 static void
1946 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1947                                           mp)
1948 {
1949   acl_main_t *am = &acl_main;
1950   vnet_sw_interface_t *swif;
1951   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1952
1953   u32 sw_if_index;
1954   unix_shared_memory_queue_t *q;
1955
1956   q = vl_api_client_index_to_input_queue (mp->client_index);
1957   if (q == 0)
1958     {
1959       return;
1960     }
1961
1962   if (mp->sw_if_index == ~0)
1963     {
1964     /* *INDENT-OFF* */
1965     pool_foreach (swif, im->sw_interfaces,
1966     ({
1967       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1968     }));
1969     /* *INDENT-ON* */
1970     }
1971   else
1972     {
1973       sw_if_index = ntohl (mp->sw_if_index);
1974       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
1975         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1976     }
1977 }
1978
1979 /* MACIP ACL API handlers */
1980
1981 static void
1982 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1983 {
1984   vl_api_macip_acl_add_reply_t *rmp;
1985   acl_main_t *am = &acl_main;
1986   int rv;
1987   u32 acl_list_index = ~0;
1988   u32 acl_count = ntohl (mp->count);
1989   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
1990
1991   if (verify_message_len (mp, expected_len, "macip_acl_add"))
1992     {
1993       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1994     }
1995   else
1996     {
1997       rv = VNET_API_ERROR_INVALID_VALUE;
1998     }
1999
2000   /* *INDENT-OFF* */
2001   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
2002   ({
2003     rmp->acl_index = htonl(acl_list_index);
2004   }));
2005   /* *INDENT-ON* */
2006 }
2007
2008 static void
2009 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
2010 {
2011   vl_api_macip_acl_add_replace_reply_t *rmp;
2012   acl_main_t *am = &acl_main;
2013   int rv;
2014   u32 acl_list_index = ntohl (mp->acl_index);
2015   u32 acl_count = ntohl (mp->count);
2016   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2017
2018   if (verify_message_len (mp, expected_len, "macip_acl_add_replace"))
2019     {
2020       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2021     }
2022   else
2023     {
2024       rv = VNET_API_ERROR_INVALID_VALUE;
2025     }
2026
2027   /* *INDENT-OFF* */
2028   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
2029   ({
2030     rmp->acl_index = htonl(acl_list_index);
2031   }));
2032   /* *INDENT-ON* */
2033 }
2034
2035 static void
2036 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
2037 {
2038   acl_main_t *am = &acl_main;
2039   vl_api_macip_acl_del_reply_t *rmp;
2040   int rv;
2041
2042   rv = macip_acl_del_list (ntohl (mp->acl_index));
2043
2044   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
2045 }
2046
2047 static void
2048   vl_api_macip_acl_interface_add_del_t_handler
2049   (vl_api_macip_acl_interface_add_del_t * mp)
2050 {
2051   acl_main_t *am = &acl_main;
2052   vl_api_macip_acl_interface_add_del_reply_t *rmp;
2053   int rv = -1;
2054   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2055   u32 sw_if_index = ntohl (mp->sw_if_index);
2056
2057   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2058     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2059   else
2060     rv =
2061       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
2062                                        ntohl (mp->acl_index));
2063
2064   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
2065 }
2066
2067 static void
2068 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
2069                         macip_acl_list_t * acl, u32 context)
2070 {
2071   vl_api_macip_acl_details_t *mp;
2072   vl_api_macip_acl_rule_t *rules;
2073   macip_acl_rule_t *r;
2074   int i;
2075   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
2076
2077   mp = vl_msg_api_alloc (msg_size);
2078   memset (mp, 0, msg_size);
2079   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
2080
2081   /* fill in the message */
2082   mp->context = context;
2083   if (acl)
2084     {
2085       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2086       mp->count = htonl (acl->count);
2087       mp->acl_index = htonl (acl - am->macip_acls);
2088       rules = mp->r;
2089       for (i = 0; i < acl->count; i++)
2090         {
2091           r = &acl->rules[i];
2092           rules[i].is_permit = r->is_permit;
2093           rules[i].is_ipv6 = r->is_ipv6;
2094           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
2095           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
2096                   sizeof (r->src_mac_mask));
2097           if (r->is_ipv6)
2098             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
2099                     sizeof (r->src_ip_addr.ip6));
2100           else
2101             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
2102                     sizeof (r->src_ip_addr.ip4));
2103           rules[i].src_ip_prefix_len = r->src_prefixlen;
2104         }
2105     }
2106   else
2107     {
2108       /* No martini, no party - no ACL applied to this interface. */
2109       mp->acl_index = ~0;
2110       mp->count = 0;
2111     }
2112
2113   vl_msg_api_send_shmem (q, (u8 *) & mp);
2114 }
2115
2116
2117 static void
2118 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
2119 {
2120   acl_main_t *am = &acl_main;
2121   macip_acl_list_t *acl;
2122
2123   unix_shared_memory_queue_t *q;
2124
2125   q = vl_api_client_index_to_input_queue (mp->client_index);
2126   if (q == 0)
2127     {
2128       return;
2129     }
2130
2131   if (mp->acl_index == ~0)
2132     {
2133       /* Just dump all ACLs for now, with sw_if_index = ~0 */
2134       pool_foreach (acl, am->macip_acls, (
2135                                            {
2136                                            send_macip_acl_details (am, q, acl,
2137                                                                    mp->
2138                                                                    context);}
2139                     ));
2140       /* *INDENT-ON* */
2141     }
2142   else
2143     {
2144       u32 acl_index = ntohl (mp->acl_index);
2145       if (!pool_is_free_index (am->macip_acls, acl_index))
2146         {
2147           acl = pool_elt_at_index (am->macip_acls, acl_index);
2148           send_macip_acl_details (am, q, acl, mp->context);
2149         }
2150     }
2151 }
2152
2153 static void
2154 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
2155                                           mp)
2156 {
2157   acl_main_t *am = &acl_main;
2158   vl_api_macip_acl_interface_get_reply_t *rmp;
2159   u32 count = vec_len (am->macip_acl_by_sw_if_index);
2160   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
2161   unix_shared_memory_queue_t *q;
2162   int i;
2163
2164   q = vl_api_client_index_to_input_queue (mp->client_index);
2165   if (q == 0)
2166     {
2167       return;
2168     }
2169
2170   rmp = vl_msg_api_alloc (msg_size);
2171   memset (rmp, 0, msg_size);
2172   rmp->_vl_msg_id =
2173     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
2174   rmp->context = mp->context;
2175   rmp->count = htonl (count);
2176   for (i = 0; i < count; i++)
2177     {
2178       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
2179     }
2180
2181   vl_msg_api_send_shmem (q, (u8 *) & rmp);
2182 }
2183
2184 static void
2185 send_macip_acl_interface_list_details (acl_main_t * am,
2186                                        unix_shared_memory_queue_t * q,
2187                                        u32 sw_if_index,
2188                                        u32 acl_index, u32 context)
2189 {
2190   vl_api_macip_acl_interface_list_details_t *rmp;
2191   /* at this time there is only ever 1 mac ip acl per interface */
2192   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
2193
2194   rmp = vl_msg_api_alloc (msg_size);
2195   memset (rmp, 0, msg_size);
2196   rmp->_vl_msg_id =
2197     ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2198
2199   /* fill in the message */
2200   rmp->context = context;
2201   rmp->count = 1;
2202   rmp->sw_if_index = htonl (sw_if_index);
2203   rmp->acls[0] = htonl (acl_index);
2204
2205   vl_msg_api_send_shmem (q, (u8 *) & rmp);
2206 }
2207
2208 static void
2209   vl_api_macip_acl_interface_list_dump_t_handler
2210   (vl_api_macip_acl_interface_list_dump_t * mp)
2211 {
2212   unix_shared_memory_queue_t *q;
2213   acl_main_t *am = &acl_main;
2214   u32 sw_if_index = ntohl (mp->sw_if_index);
2215
2216   q = vl_api_client_index_to_input_queue (mp->client_index);
2217   if (q == 0)
2218     {
2219       return;
2220     }
2221
2222   if (sw_if_index == ~0)
2223     {
2224       vec_foreach_index (sw_if_index, am->macip_acl_by_sw_if_index)
2225       {
2226         if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2227           {
2228             send_macip_acl_interface_list_details (am, q, sw_if_index,
2229                                                    am->macip_acl_by_sw_if_index
2230                                                    [sw_if_index],
2231                                                    mp->context);
2232           }
2233       }
2234     }
2235   else
2236     {
2237       if (vec_len (am->macip_acl_by_sw_if_index) > sw_if_index)
2238         {
2239           send_macip_acl_interface_list_details (am, q, sw_if_index,
2240                                                  am->macip_acl_by_sw_if_index
2241                                                  [sw_if_index], mp->context);
2242         }
2243     }
2244 }
2245
2246 /* Set up the API message handling tables */
2247 static clib_error_t *
2248 acl_plugin_api_hookup (vlib_main_t * vm)
2249 {
2250   acl_main_t *am = &acl_main;
2251 #define _(N,n)                                                  \
2252     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
2253                            #n,                                  \
2254                            vl_api_##n##_t_handler,              \
2255                            vl_noop_handler,                     \
2256                            vl_api_##n##_t_endian,               \
2257                            vl_api_##n##_t_print,                \
2258                            sizeof(vl_api_##n##_t), 1);
2259   foreach_acl_plugin_api_msg;
2260 #undef _
2261
2262   return 0;
2263 }
2264
2265 #define vl_msg_name_crc_list
2266 #include <acl/acl_all_api_h.h>
2267 #undef vl_msg_name_crc_list
2268
2269 static void
2270 setup_message_id_table (acl_main_t * am, api_main_t * apim)
2271 {
2272 #define _(id,n,crc) \
2273   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
2274   foreach_vl_msg_name_crc_acl;
2275 #undef _
2276 }
2277
2278 static void
2279 acl_setup_fa_nodes (void)
2280 {
2281   vlib_main_t *vm = vlib_get_main ();
2282   acl_main_t *am = &acl_main;
2283   vlib_node_t *n, *n4, *n6;
2284
2285   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
2286   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
2287   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
2288
2289
2290   am->l2_input_classify_next_acl_ip4 =
2291     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
2292   am->l2_input_classify_next_acl_ip6 =
2293     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
2294
2295   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
2296                                l2input_get_feat_names (),
2297                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
2298
2299   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
2300                                l2input_get_feat_names (),
2301                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
2302
2303
2304   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
2305   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
2306   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
2307
2308   am->l2_output_classify_next_acl_ip4 =
2309     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
2310   am->l2_output_classify_next_acl_ip6 =
2311     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
2312
2313   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
2314                                l2output_get_feat_names (),
2315                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
2316
2317   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
2318                                l2output_get_feat_names (),
2319                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
2320 }
2321
2322 static void
2323 acl_set_timeout_sec (int timeout_type, u32 value)
2324 {
2325   acl_main_t *am = &acl_main;
2326   clib_time_t *ct = &am->vlib_main->clib_time;
2327
2328   if (timeout_type < ACL_N_TIMEOUTS)
2329     {
2330       am->session_timeout_sec[timeout_type] = value;
2331     }
2332   else
2333     {
2334       clib_warning ("Unknown timeout type %d", timeout_type);
2335       return;
2336     }
2337   am->session_timeout[timeout_type] =
2338     (u64) (((f64) value) / ct->seconds_per_clock);
2339 }
2340
2341 static void
2342 acl_set_session_max_entries (u32 value)
2343 {
2344   acl_main_t *am = &acl_main;
2345   am->fa_conn_table_max_entries = value;
2346 }
2347
2348 static int
2349 acl_set_skip_ipv6_eh (u32 eh, u32 value)
2350 {
2351   acl_main_t *am = &acl_main;
2352
2353   if ((eh < 256) && (value < 2))
2354     {
2355       am->fa_ipv6_known_eh_bitmap =
2356         clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
2357       return 1;
2358     }
2359   else
2360     return 0;
2361 }
2362
2363
2364 static clib_error_t *
2365 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
2366 {
2367   acl_main_t *am = &acl_main;
2368   if (0 == am->acl_mheap)
2369     {
2370       /* ACL heap is not initialized, so definitely nothing to do. */
2371       return 0;
2372     }
2373   if (0 == is_add)
2374     {
2375       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2376                                  ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
2377                                  sw_if_index);
2378       /* also unapply any ACLs in case the users did not do so. */
2379       macip_acl_interface_del_acl (am, sw_if_index);
2380       acl_interface_reset_inout_acls (sw_if_index, 0);
2381       acl_interface_reset_inout_acls (sw_if_index, 1);
2382     }
2383   return 0;
2384 }
2385
2386 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
2387
2388
2389
2390 static clib_error_t *
2391 acl_set_aclplugin_fn (vlib_main_t * vm,
2392                       unformat_input_t * input, vlib_cli_command_t * cmd)
2393 {
2394   clib_error_t *error = 0;
2395   u32 timeout = 0;
2396   u32 val = 0;
2397   u32 eh_val = 0;
2398   uword memory_size = 0;
2399   acl_main_t *am = &acl_main;
2400
2401   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
2402     {
2403       if (!acl_set_skip_ipv6_eh (eh_val, val))
2404         {
2405           error = clib_error_return (0, "expecting eh=0..255, value=0..1");
2406         }
2407       goto done;
2408     }
2409   if (unformat (input, "use-hash-acl-matching %u", &val))
2410     {
2411       am->use_hash_acl_matching = (val != 0);
2412       goto done;
2413     }
2414   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
2415     {
2416       am->l4_match_nonfirst_fragment = (val != 0);
2417       goto done;
2418     }
2419   if (unformat (input, "heap"))
2420     {
2421       if (unformat (input, "main"))
2422         {
2423           if (unformat (input, "validate %u", &val))
2424             acl_plugin_acl_set_validate_heap (am, val);
2425           else if (unformat (input, "trace %u", &val))
2426             acl_plugin_acl_set_trace_heap (am, val);
2427           goto done;
2428         }
2429       else if (unformat (input, "hash"))
2430         {
2431           if (unformat (input, "validate %u", &val))
2432             acl_plugin_hash_acl_set_validate_heap (am, val);
2433           else if (unformat (input, "trace %u", &val))
2434             acl_plugin_hash_acl_set_trace_heap (am, val);
2435           goto done;
2436         }
2437       goto done;
2438     }
2439   if (unformat (input, "session"))
2440     {
2441       if (unformat (input, "table"))
2442         {
2443           /* The commands here are for tuning/testing. No user-serviceable parts inside */
2444           if (unformat (input, "max-entries"))
2445             {
2446               if (!unformat (input, "%u", &val))
2447                 {
2448                   error = clib_error_return (0,
2449                                              "expecting maximum number of entries, got `%U`",
2450                                              format_unformat_error, input);
2451                   goto done;
2452                 }
2453               else
2454                 {
2455                   acl_set_session_max_entries (val);
2456                   goto done;
2457                 }
2458             }
2459           if (unformat (input, "hash-table-buckets"))
2460             {
2461               if (!unformat (input, "%u", &val))
2462                 {
2463                   error = clib_error_return (0,
2464                                              "expecting maximum number of hash table buckets, got `%U`",
2465                                              format_unformat_error, input);
2466                   goto done;
2467                 }
2468               else
2469                 {
2470                   am->fa_conn_table_hash_num_buckets = val;
2471                   goto done;
2472                 }
2473             }
2474           if (unformat (input, "hash-table-memory"))
2475             {
2476               if (!unformat (input, "%U", unformat_memory_size, &memory_size))
2477                 {
2478                   error = clib_error_return (0,
2479                                              "expecting maximum amount of hash table memory, got `%U`",
2480                                              format_unformat_error, input);
2481                   goto done;
2482                 }
2483               else
2484                 {
2485                   am->fa_conn_table_hash_memory_size = memory_size;
2486                   goto done;
2487                 }
2488             }
2489           goto done;
2490         }
2491       if (unformat (input, "timeout"))
2492         {
2493           if (unformat (input, "udp"))
2494             {
2495               if (unformat (input, "idle"))
2496                 {
2497                   if (!unformat (input, "%u", &timeout))
2498                     {
2499                       error = clib_error_return (0,
2500                                                  "expecting timeout value in seconds, got `%U`",
2501                                                  format_unformat_error,
2502                                                  input);
2503                       goto done;
2504                     }
2505                   else
2506                     {
2507                       acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
2508                       goto done;
2509                     }
2510                 }
2511             }
2512           if (unformat (input, "tcp"))
2513             {
2514               if (unformat (input, "idle"))
2515                 {
2516                   if (!unformat (input, "%u", &timeout))
2517                     {
2518                       error = clib_error_return (0,
2519                                                  "expecting timeout value in seconds, got `%U`",
2520                                                  format_unformat_error,
2521                                                  input);
2522                       goto done;
2523                     }
2524                   else
2525                     {
2526                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
2527                       goto done;
2528                     }
2529                 }
2530               if (unformat (input, "transient"))
2531                 {
2532                   if (!unformat (input, "%u", &timeout))
2533                     {
2534                       error = clib_error_return (0,
2535                                                  "expecting timeout value in seconds, got `%U`",
2536                                                  format_unformat_error,
2537                                                  input);
2538                       goto done;
2539                     }
2540                   else
2541                     {
2542                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
2543                                            timeout);
2544                       goto done;
2545                     }
2546                 }
2547             }
2548           goto done;
2549         }
2550     }
2551 done:
2552   return error;
2553 }
2554
2555 static u8 *
2556 my_format_mac_address (u8 * s, va_list * args)
2557 {
2558   u8 *a = va_arg (*args, u8 *);
2559   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
2560                  a[0], a[1], a[2], a[3], a[4], a[5]);
2561 }
2562
2563 static inline u8 *
2564 my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
2565 {
2566   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
2567
2568   out = format (out, "%s action %d ip %U/%d mac %U mask %U",
2569                 a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
2570                 format_ip46_address, &a->src_ip_addr,
2571                 a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
2572                 a->src_prefixlen,
2573                 my_format_mac_address, a->src_mac,
2574                 my_format_mac_address, a->src_mac_mask);
2575   return (out);
2576 }
2577
2578 static void
2579 macip_acl_print (acl_main_t * am, u32 macip_acl_index)
2580 {
2581   vlib_main_t *vm = am->vlib_main;
2582   int i;
2583
2584   /* Don't try to print someone else's memory */
2585   if (macip_acl_index > vec_len (am->macip_acls))
2586     return;
2587
2588   macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
2589   int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
2590
2591   vlib_cli_output (vm,
2592                    "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
2593                    macip_acl_index, a->count, vec_len (a->rules), a->tag,
2594                    free_pool_slot);
2595   vlib_cli_output (vm,
2596                    "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
2597                    a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
2598   for (i = 0; i < vec_len (a->rules); i++)
2599     vlib_cli_output (vm, "    rule %d: %U\n", i,
2600                      my_macip_acl_rule_t_pretty_format,
2601                      vec_elt_at_index (a->rules, i));
2602
2603 }
2604
2605 static clib_error_t *
2606 acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
2607                                  unformat_input_t * input,
2608                                  vlib_cli_command_t * cmd)
2609 {
2610   clib_error_t *error = 0;
2611   acl_main_t *am = &acl_main;
2612   int i;
2613   for (i = 0; i < vec_len (am->macip_acls); i++)
2614     macip_acl_print (am, i);
2615   return error;
2616 }
2617
2618 static clib_error_t *
2619 acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
2620                                        unformat_input_t * input,
2621                                        vlib_cli_command_t * cmd)
2622 {
2623   clib_error_t *error = 0;
2624   acl_main_t *am = &acl_main;
2625   int i;
2626   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
2627     {
2628       vlib_cli_output (vm, "  sw_if_index %d: %d\n", i,
2629                        vec_elt (am->macip_acl_by_sw_if_index, i));
2630     }
2631   return error;
2632 }
2633
2634 #define PRINT_AND_RESET(vm, out0) do { vlib_cli_output(vm, "%v", out0); vec_reset_length(out0); } while(0)
2635 static void
2636 acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
2637 {
2638   acl_rule_t *r;
2639   u8 *out0 = format (0, "acl-index %u count %u tag {%s}\n", acl_index,
2640                      am->acls[acl_index].count, am->acls[acl_index].tag);
2641   int j;
2642   PRINT_AND_RESET (vm, out0);
2643   for (j = 0; j < am->acls[acl_index].count; j++)
2644     {
2645       r = &am->acls[acl_index].rules[j];
2646       out0 = format (out0, "  %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
2647       out0 = format_acl_action (out0, r->is_permit);
2648       out0 = format (out0, " src %U/%d", format_ip46_address, &r->src,
2649                      r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
2650                      r->src_prefixlen);
2651       out0 =
2652         format (out0, " dst %U/%d", format_ip46_address, &r->dst,
2653                 r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, r->dst_prefixlen);
2654       out0 = format (out0, " proto %d", r->proto);
2655       out0 = format (out0, " sport %d", r->src_port_or_type_first);
2656       if (r->src_port_or_type_first != r->src_port_or_type_last)
2657         {
2658           out0 = format (out0, "-%d", r->src_port_or_type_last);
2659         }
2660       out0 = format (out0, " dport %d", r->dst_port_or_code_first);
2661       if (r->dst_port_or_code_first != r->dst_port_or_code_last)
2662         {
2663           out0 = format (out0, "-%d", r->dst_port_or_code_last);
2664         }
2665       if (r->tcp_flags_mask || r->tcp_flags_value)
2666         {
2667           out0 =
2668             format (out0, " tcpflags %d mask %d", r->tcp_flags_value,
2669                     r->tcp_flags_mask);
2670         }
2671       out0 = format (out0, "\n");
2672       PRINT_AND_RESET (vm, out0);
2673     }
2674 }
2675
2676 #undef PRINT_AND_RESET
2677
2678 static void
2679 acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
2680 {
2681   u32 i;
2682   vlib_main_t *vm = am->vlib_main;
2683
2684   for (i = 0; i < vec_len (am->acls); i++)
2685     {
2686       if (acl_is_not_defined (am, i))
2687         {
2688           /* don't attempt to show the ACLs that do not exist */
2689           continue;
2690         }
2691       if ((acl_index != ~0) && (acl_index != i))
2692         {
2693           continue;
2694         }
2695       acl_print_acl (vm, am, i);
2696
2697       if (i < vec_len (am->input_sw_if_index_vec_by_acl))
2698         {
2699           vlib_cli_output (vm, "  applied inbound on sw_if_index: %U\n",
2700                            format_vec32, am->input_sw_if_index_vec_by_acl[i],
2701                            "%d");
2702         }
2703       if (i < vec_len (am->output_sw_if_index_vec_by_acl))
2704         {
2705           vlib_cli_output (vm, "  applied outbound on sw_if_index: %U\n",
2706                            format_vec32, am->output_sw_if_index_vec_by_acl[i],
2707                            "%d");
2708         }
2709     }
2710 }
2711
2712 static clib_error_t *
2713 acl_show_aclplugin_acl_fn (vlib_main_t * vm,
2714                            unformat_input_t * input, vlib_cli_command_t * cmd)
2715 {
2716   clib_error_t *error = 0;
2717   acl_main_t *am = &acl_main;
2718
2719   u32 acl_index = ~0;
2720   unformat (input, "index %u", &acl_index);
2721
2722   acl_plugin_show_acl (am, acl_index);
2723   return error;
2724 }
2725
2726 static void
2727 acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl)
2728 {
2729   vlib_main_t *vm = am->vlib_main;
2730   u32 swi;
2731   u32 *pj;
2732   for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
2733        (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
2734     {
2735       /* if we need a particular interface, skip all the others */
2736       if ((sw_if_index != ~0) && (sw_if_index != swi))
2737         continue;
2738
2739       vlib_cli_output (vm, "sw_if_index %d:\n", swi);
2740
2741       if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
2742           (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
2743         {
2744           vlib_cli_output (vm, "  input acl(s): %U", format_vec32,
2745                            am->input_acl_vec_by_sw_if_index[swi], "%d");
2746           if (show_acl)
2747             {
2748               vlib_cli_output (vm, "\n");
2749               vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
2750               {
2751                 acl_print_acl (vm, am, *pj);
2752               }
2753               vlib_cli_output (vm, "\n");
2754             }
2755         }
2756
2757       if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
2758           (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
2759         {
2760           vlib_cli_output (vm, "  output acl(s): %U", format_vec32,
2761                            am->output_acl_vec_by_sw_if_index[swi], "%d");
2762           if (show_acl)
2763             {
2764               vlib_cli_output (vm, "\n");
2765               vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
2766               {
2767                 acl_print_acl (vm, am, *pj);
2768               }
2769               vlib_cli_output (vm, "\n");
2770             }
2771         }
2772     }
2773
2774 }
2775
2776 static clib_error_t *
2777 acl_show_aclplugin_interface_fn (vlib_main_t * vm,
2778                                  unformat_input_t * input,
2779                                  vlib_cli_command_t * cmd)
2780 {
2781   clib_error_t *error = 0;
2782   acl_main_t *am = &acl_main;
2783
2784   u32 sw_if_index = ~0;
2785   unformat (input, "sw_if_index %u", &sw_if_index);
2786   int show_acl = unformat (input, "acl");
2787
2788   acl_plugin_show_interface (am, sw_if_index, show_acl);
2789   return error;
2790 }
2791
2792 static clib_error_t *
2793 acl_show_aclplugin_memory_fn (vlib_main_t * vm,
2794                               unformat_input_t * input,
2795                               vlib_cli_command_t * cmd)
2796 {
2797   clib_error_t *error = 0;
2798   acl_main_t *am = &acl_main;
2799
2800   vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
2801   if (am->acl_mheap)
2802     {
2803       vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
2804     }
2805   else
2806     {
2807       vlib_cli_output (vm, " Not initialized\n");
2808     }
2809   vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
2810   if (am->hash_lookup_mheap)
2811     {
2812       vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
2813     }
2814   else
2815     {
2816       vlib_cli_output (vm, " Not initialized\n");
2817     }
2818   return error;
2819 }
2820
2821 static void
2822 acl_plugin_show_sessions (acl_main_t * am,
2823                           u32 show_session_thread_id,
2824                           u32 show_session_session_index)
2825 {
2826   vlib_main_t *vm = am->vlib_main;
2827   u16 wk;
2828   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2829   vnet_sw_interface_t *swif;
2830
2831   {
2832     u64 n_adds = am->fa_session_total_adds;
2833     u64 n_dels = am->fa_session_total_dels;
2834     vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
2835                      n_dels, n_adds - n_dels);
2836   }
2837   vlib_cli_output (vm, "\n\nPer-thread data:");
2838   for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
2839     {
2840       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2841       vlib_cli_output (vm, "Thread #%d:", wk);
2842       if (show_session_thread_id == wk
2843           && show_session_session_index < pool_len (pw->fa_sessions_pool))
2844         {
2845           vlib_cli_output (vm, "  session index %u:",
2846                            show_session_session_index);
2847           fa_session_t *sess =
2848             pw->fa_sessions_pool + show_session_session_index;
2849           u64 *m = (u64 *) & sess->info;
2850           vlib_cli_output (vm,
2851                            "    info: %016llx %016llx %016llx %016llx %016llx %016llx",
2852                            m[0], m[1], m[2], m[3], m[4], m[5]);
2853           vlib_cli_output (vm, "    sw_if_index: %u", sess->sw_if_index);
2854           vlib_cli_output (vm, "    tcp_flags_seen: %x",
2855                            sess->tcp_flags_seen.as_u16);
2856           vlib_cli_output (vm, "    last active time: %lu",
2857                            sess->last_active_time);
2858           vlib_cli_output (vm, "    thread index: %u", sess->thread_index);
2859           vlib_cli_output (vm, "    link enqueue time: %lu",
2860                            sess->link_enqueue_time);
2861           vlib_cli_output (vm, "    link next index: %u",
2862                            sess->link_next_idx);
2863           vlib_cli_output (vm, "    link prev index: %u",
2864                            sess->link_prev_idx);
2865           vlib_cli_output (vm, "    link list id: %u", sess->link_list_id);
2866         }
2867       vlib_cli_output (vm, "  connection add/del stats:", wk);
2868       pool_foreach (swif, im->sw_interfaces, (
2869                                                {
2870                                                u32 sw_if_index =
2871                                                swif->sw_if_index;
2872                                                u64 n_adds =
2873                                                sw_if_index <
2874                                                vec_len
2875                                                (pw->fa_session_adds_by_sw_if_index)
2876                                                ?
2877                                                pw->fa_session_adds_by_sw_if_index
2878                                                [sw_if_index] : 0;
2879                                                u64 n_dels =
2880                                                sw_if_index <
2881                                                vec_len
2882                                                (pw->fa_session_dels_by_sw_if_index)
2883                                                ?
2884                                                pw->fa_session_dels_by_sw_if_index
2885                                                [sw_if_index] : 0;
2886                                                vlib_cli_output (vm,
2887                                                                 "    sw_if_index %d: add %lu - del %lu = %lu",
2888                                                                 sw_if_index,
2889                                                                 n_adds,
2890                                                                 n_dels,
2891                                                                 n_adds -
2892                                                                 n_dels);
2893                                                }
2894                     ));
2895
2896       vlib_cli_output (vm, "  connection timeout type lists:", wk);
2897       u8 tt = 0;
2898       for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
2899         {
2900           u32 head_session_index = pw->fa_conn_list_head[tt];
2901           vlib_cli_output (vm, "  fa_conn_list_head[%d]: %d", tt,
2902                            head_session_index);
2903           if (~0 != head_session_index)
2904             {
2905               fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
2906               vlib_cli_output (vm, "    last active time: %lu",
2907                                sess->last_active_time);
2908               vlib_cli_output (vm, "    link enqueue time: %lu",
2909                                sess->link_enqueue_time);
2910             }
2911         }
2912
2913       vlib_cli_output (vm, "  Next expiry time: %lu", pw->next_expiry_time);
2914       vlib_cli_output (vm, "  Requeue until time: %lu",
2915                        pw->requeue_until_time);
2916       vlib_cli_output (vm, "  Current time wait interval: %lu",
2917                        pw->current_time_wait_interval);
2918       vlib_cli_output (vm, "  Count of deleted sessions: %lu",
2919                        pw->cnt_deleted_sessions);
2920       vlib_cli_output (vm, "  Delete already deleted: %lu",
2921                        pw->cnt_already_deleted_sessions);
2922       vlib_cli_output (vm, "  Session timers restarted: %lu",
2923                        pw->cnt_session_timer_restarted);
2924       vlib_cli_output (vm, "  Swipe until this time: %lu",
2925                        pw->swipe_end_time);
2926       vlib_cli_output (vm, "  sw_if_index serviced bitmap: %U",
2927                        format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
2928       vlib_cli_output (vm, "  pending clear intfc bitmap : %U",
2929                        format_bitmap_hex,
2930                        pw->pending_clear_sw_if_index_bitmap);
2931       vlib_cli_output (vm, "  clear in progress: %u", pw->clear_in_process);
2932       vlib_cli_output (vm, "  interrupt is pending: %d",
2933                        pw->interrupt_is_pending);
2934       vlib_cli_output (vm, "  interrupt is needed: %d",
2935                        pw->interrupt_is_needed);
2936       vlib_cli_output (vm, "  interrupt is unwanted: %d",
2937                        pw->interrupt_is_unwanted);
2938       vlib_cli_output (vm, "  interrupt generation: %d",
2939                        pw->interrupt_generation);
2940     }
2941   vlib_cli_output (vm, "\n\nConn cleaner thread counters:");
2942 #define _(cnt, desc) vlib_cli_output(vm, "             %20lu: %s", am->cnt, desc);
2943   foreach_fa_cleaner_counter;
2944 #undef _
2945   vlib_cli_output (vm, "Interrupt generation: %d",
2946                    am->fa_interrupt_generation);
2947   vlib_cli_output (vm,
2948                    "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
2949                    am->fa_min_deleted_sessions_per_interval,
2950                    am->fa_max_deleted_sessions_per_interval,
2951                    am->fa_cleaner_wait_time_increment * 1000.0,
2952                    ((f64) am->fa_current_cleaner_timer_wait_interval) *
2953                    1000.0 / (f64) vm->clib_time.clocks_per_second);
2954 }
2955
2956 static clib_error_t *
2957 acl_show_aclplugin_sessions_fn (vlib_main_t * vm,
2958                                 unformat_input_t * input,
2959                                 vlib_cli_command_t * cmd)
2960 {
2961   clib_error_t *error = 0;
2962   acl_main_t *am = &acl_main;
2963
2964   u32 show_bihash_verbose = 0;
2965   u32 show_session_thread_id = ~0;
2966   u32 show_session_session_index = ~0;
2967   unformat (input, "thread %u index %u", &show_session_thread_id,
2968             &show_session_session_index);
2969   unformat (input, "verbose %u", &show_bihash_verbose);
2970
2971   acl_plugin_show_sessions (am, show_session_thread_id,
2972                             show_session_session_index);
2973   show_fa_sessions_hash (vm, show_bihash_verbose);
2974   return error;
2975 }
2976
2977 static void
2978 acl_plugin_show_tables_mask_type (acl_main_t * am)
2979 {
2980   vlib_main_t *vm = am->vlib_main;
2981   ace_mask_type_entry_t *mte;
2982
2983   vlib_cli_output (vm, "Mask-type entries:");
2984     /* *INDENT-OFF* */
2985     pool_foreach(mte, am->ace_mask_type_pool,
2986     ({
2987       vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
2988                     mte - am->ace_mask_type_pool,
2989                     mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
2990                     mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
2991     }));
2992     /* *INDENT-ON* */
2993 }
2994
2995 static void
2996 acl_plugin_show_tables_acl_hash_info (acl_main_t * am, u32 acl_index)
2997 {
2998   vlib_main_t *vm = am->vlib_main;
2999   u32 i, j;
3000   u64 *m;
3001   vlib_cli_output (vm, "Mask-ready ACL representations\n");
3002   for (i = 0; i < vec_len (am->hash_acl_infos); i++)
3003     {
3004       if ((acl_index != ~0) && (acl_index != i))
3005         {
3006           continue;
3007         }
3008       hash_acl_info_t *ha = &am->hash_acl_infos[i];
3009       vlib_cli_output (vm, "acl-index %u bitmask-ready layout\n", i);
3010       vlib_cli_output (vm, "  applied  inbound on sw_if_index list: %U\n",
3011                        format_vec32, ha->inbound_sw_if_index_list, "%d");
3012       vlib_cli_output (vm, "  applied outbound on sw_if_index list: %U\n",
3013                        format_vec32, ha->outbound_sw_if_index_list, "%d");
3014       vlib_cli_output (vm, "  mask type index bitmap: %U\n",
3015                        format_bitmap_hex, ha->mask_type_index_bitmap);
3016       for (j = 0; j < vec_len (ha->rules); j++)
3017         {
3018           hash_ace_info_t *pa = &ha->rules[j];
3019           m = (u64 *) & pa->match;
3020           vlib_cli_output (vm,
3021                            "    %4d: %016llx %016llx %016llx %016llx %016llx %016llx mask index %d acl %d rule %d action %d src/dst portrange not ^2: %d,%d\n",
3022                            j, m[0], m[1], m[2], m[3], m[4], m[5],
3023                            pa->mask_type_index, pa->acl_index, pa->ace_index,
3024                            pa->action, pa->src_portrange_not_powerof2,
3025                            pa->dst_portrange_not_powerof2);
3026         }
3027     }
3028 }
3029
3030 static void
3031 acl_plugin_print_pae (vlib_main_t * vm, int j, applied_hash_ace_entry_t * pae)
3032 {
3033   vlib_cli_output (vm,
3034                    "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld",
3035                    j, pae->acl_index, pae->ace_index, pae->action,
3036                    pae->hash_ace_info_index, pae->next_applied_entry_index,
3037                    pae->prev_applied_entry_index,
3038                    pae->tail_applied_entry_index, pae->hitcount);
3039 }
3040
3041 static void
3042 acl_plugin_show_tables_applied_info (acl_main_t * am, u32 sw_if_index)
3043 {
3044   vlib_main_t *vm = am->vlib_main;
3045   u32 swi, j;
3046   vlib_cli_output (vm, "Applied lookup entries for interfaces");
3047
3048   for (swi = 0;
3049        (swi < vec_len (am->input_applied_hash_acl_info_by_sw_if_index))
3050        || (swi < vec_len (am->output_applied_hash_acl_info_by_sw_if_index))
3051        || (swi < vec_len (am->input_hash_entry_vec_by_sw_if_index))
3052        || (swi < vec_len (am->output_hash_entry_vec_by_sw_if_index)); swi++)
3053     {
3054       if ((sw_if_index != ~0) && (sw_if_index != swi))
3055         {
3056           continue;
3057         }
3058       vlib_cli_output (vm, "sw_if_index %d:", swi);
3059       if (swi < vec_len (am->input_applied_hash_acl_info_by_sw_if_index))
3060         {
3061           applied_hash_acl_info_t *pal =
3062             &am->input_applied_hash_acl_info_by_sw_if_index[swi];
3063           vlib_cli_output (vm, "  input lookup mask_type_index_bitmap: %U",
3064                            format_bitmap_hex, pal->mask_type_index_bitmap);
3065           vlib_cli_output (vm, "  input applied acls: %U", format_vec32,
3066                            pal->applied_acls, "%d");
3067         }
3068       if (swi < vec_len (am->input_hash_entry_vec_by_sw_if_index))
3069         {
3070           vlib_cli_output (vm, "  input lookup applied entries:");
3071           for (j = 0;
3072                j < vec_len (am->input_hash_entry_vec_by_sw_if_index[swi]);
3073                j++)
3074             {
3075               acl_plugin_print_pae (vm, j,
3076                                     &am->input_hash_entry_vec_by_sw_if_index
3077                                     [swi][j]);
3078             }
3079         }
3080
3081       if (swi < vec_len (am->output_applied_hash_acl_info_by_sw_if_index))
3082         {
3083           applied_hash_acl_info_t *pal =
3084             &am->output_applied_hash_acl_info_by_sw_if_index[swi];
3085           vlib_cli_output (vm, "  output lookup mask_type_index_bitmap: %U",
3086                            format_bitmap_hex, pal->mask_type_index_bitmap);
3087           vlib_cli_output (vm, "  output applied acls: %U", format_vec32,
3088                            pal->applied_acls, "%d");
3089         }
3090       if (swi < vec_len (am->output_hash_entry_vec_by_sw_if_index))
3091         {
3092           vlib_cli_output (vm, "  output lookup applied entries:");
3093           for (j = 0;
3094                j < vec_len (am->output_hash_entry_vec_by_sw_if_index[swi]);
3095                j++)
3096             {
3097               acl_plugin_print_pae (vm, j,
3098                                     &am->output_hash_entry_vec_by_sw_if_index
3099                                     [swi][j]);
3100             }
3101         }
3102     }
3103 }
3104
3105 static void
3106 acl_plugin_show_tables_bihash (acl_main_t * am, u32 show_bihash_verbose)
3107 {
3108   vlib_main_t *vm = am->vlib_main;
3109   show_hash_acl_hash (vm, am, show_bihash_verbose);
3110 }
3111
3112 static clib_error_t *
3113 acl_show_aclplugin_tables_fn (vlib_main_t * vm,
3114                               unformat_input_t * input,
3115                               vlib_cli_command_t * cmd)
3116 {
3117   clib_error_t *error = 0;
3118   acl_main_t *am = &acl_main;
3119
3120   u32 acl_index = ~0;
3121   u32 sw_if_index = ~0;
3122   int show_acl_hash_info = 0;
3123   int show_applied_info = 0;
3124   int show_mask_type = 0;
3125   int show_bihash = 0;
3126   u32 show_bihash_verbose = 0;
3127
3128   if (unformat (input, "acl"))
3129     {
3130       show_acl_hash_info = 1;
3131       /* mask-type is handy to see as well right there */
3132       show_mask_type = 1;
3133       unformat (input, "index %u", &acl_index);
3134     }
3135   else if (unformat (input, "applied"))
3136     {
3137       show_applied_info = 1;
3138       unformat (input, "sw_if_index %u", &sw_if_index);
3139     }
3140   else if (unformat (input, "mask"))
3141     {
3142       show_mask_type = 1;
3143     }
3144   else if (unformat (input, "hash"))
3145     {
3146       show_bihash = 1;
3147       unformat (input, "verbose %u", &show_bihash_verbose);
3148     }
3149
3150   if (!
3151       (show_mask_type || show_acl_hash_info || show_applied_info
3152        || show_bihash))
3153     {
3154       /* if no qualifiers specified, show all */
3155       show_mask_type = 1;
3156       show_acl_hash_info = 1;
3157       show_applied_info = 1;
3158       show_bihash = 1;
3159     }
3160   if (show_mask_type)
3161     acl_plugin_show_tables_mask_type (am);
3162   if (show_acl_hash_info)
3163     acl_plugin_show_tables_acl_hash_info (am, acl_index);
3164   if (show_applied_info)
3165     acl_plugin_show_tables_applied_info (am, sw_if_index);
3166   if (show_bihash)
3167     acl_plugin_show_tables_bihash (am, show_bihash_verbose);
3168
3169   return error;
3170 }
3171
3172 static clib_error_t *
3173 acl_clear_aclplugin_fn (vlib_main_t * vm,
3174                         unformat_input_t * input, vlib_cli_command_t * cmd)
3175 {
3176   clib_error_t *error = 0;
3177   acl_main_t *am = &acl_main;
3178   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
3179                              ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
3180   return error;
3181 }
3182
3183  /* *INDENT-OFF* */
3184 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
3185     .path = "set acl-plugin",
3186     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
3187     .function = acl_set_aclplugin_fn,
3188 };
3189
3190 VLIB_CLI_COMMAND (aclplugin_show_acl_command, static) = {
3191     .path = "show acl-plugin acl",
3192     .short_help = "show acl-plugin acl [index N]",
3193     .function = acl_show_aclplugin_acl_fn,
3194 };
3195
3196 VLIB_CLI_COMMAND (aclplugin_show_interface_command, static) = {
3197     .path = "show acl-plugin interface",
3198     .short_help = "show acl-plugin interface [sw_if_index N] [acl]",
3199     .function = acl_show_aclplugin_interface_fn,
3200 };
3201
3202 VLIB_CLI_COMMAND (aclplugin_show_memory_command, static) = {
3203     .path = "show acl-plugin memory",
3204     .short_help = "show acl-plugin memory",
3205     .function = acl_show_aclplugin_memory_fn,
3206 };
3207
3208 VLIB_CLI_COMMAND (aclplugin_show_sessions_command, static) = {
3209     .path = "show acl-plugin sessions",
3210     .short_help = "show acl-plugin sessions",
3211     .function = acl_show_aclplugin_sessions_fn,
3212 };
3213
3214 VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
3215     .path = "show acl-plugin tables",
3216     .short_help = "show acl-plugin tables [ acl [index N] | applied [ sw_if_index N ] | mask | hash [verbose N] ]",
3217     .function = acl_show_aclplugin_tables_fn,
3218 };
3219
3220 VLIB_CLI_COMMAND (aclplugin_show_macip_acl_command, static) = {
3221     .path = "show acl-plugin macip acl",
3222     .short_help = "show acl-plugin macip acl",
3223     .function = acl_show_aclplugin_macip_acl_fn,
3224 };
3225
3226 VLIB_CLI_COMMAND (aclplugin_show_macip_interface_command, static) = {
3227     .path = "show acl-plugin macip interface",
3228     .short_help = "show acl-plugin macip interface",
3229     .function = acl_show_aclplugin_macip_interface_fn,
3230 };
3231
3232 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
3233     .path = "clear acl-plugin sessions",
3234     .short_help = "clear acl-plugin sessions",
3235     .function = acl_clear_aclplugin_fn,
3236 };
3237 /* *INDENT-ON* */
3238
3239 static clib_error_t *
3240 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
3241 {
3242   acl_main_t *am = &acl_main;
3243   u32 conn_table_hash_buckets;
3244   u32 conn_table_hash_memory_size;
3245   u32 conn_table_max_entries;
3246   u32 main_heap_size;
3247   u32 hash_heap_size;
3248   u32 hash_lookup_hash_buckets;
3249   u32 hash_lookup_hash_memory;
3250
3251   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3252     {
3253       if (unformat
3254           (input, "connection hash buckets %d", &conn_table_hash_buckets))
3255         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
3256       else if (unformat (input, "connection hash memory %d",
3257                          &conn_table_hash_memory_size))
3258         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
3259       else if (unformat (input, "connection count max %d",
3260                          &conn_table_max_entries))
3261         am->fa_conn_table_max_entries = conn_table_max_entries;
3262       else if (unformat (input, "main heap size %d", &main_heap_size))
3263         am->acl_mheap_size = main_heap_size;
3264       else if (unformat (input, "hash lookup heap size %d", &hash_heap_size))
3265         am->hash_lookup_mheap_size = hash_heap_size;
3266       else if (unformat (input, "hash lookup hash buckets %d",
3267                          &hash_lookup_hash_buckets))
3268         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
3269       else if (unformat (input, "hash lookup hash memory %d",
3270                          &hash_lookup_hash_memory))
3271         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
3272       else
3273         return clib_error_return (0, "unknown input '%U'",
3274                                   format_unformat_error, input);
3275     }
3276   return 0;
3277 }
3278
3279 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
3280
3281 static clib_error_t *
3282 acl_init (vlib_main_t * vm)
3283 {
3284   acl_main_t *am = &acl_main;
3285   clib_error_t *error = 0;
3286   memset (am, 0, sizeof (*am));
3287   am->vlib_main = vm;
3288   am->vnet_main = vnet_get_main ();
3289
3290   u8 *name = format (0, "acl_%08x%c", api_version, 0);
3291
3292   /* Ask for a correctly-sized block of API message decode slots */
3293   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
3294                                             VL_MSG_FIRST_AVAILABLE);
3295
3296   error = acl_plugin_api_hookup (vm);
3297
3298   /* Add our API messages to the global name_crc hash table */
3299   setup_message_id_table (am, &api_main);
3300
3301   vec_free (name);
3302
3303   acl_setup_fa_nodes ();
3304
3305   am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
3306   am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
3307
3308   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
3309   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
3310
3311   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
3312     TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
3313   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
3314     TCP_SESSION_IDLE_TIMEOUT_SEC;
3315   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
3316     UDP_SESSION_IDLE_TIMEOUT_SEC;
3317
3318   am->fa_conn_table_hash_num_buckets =
3319     ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
3320   am->fa_conn_table_hash_memory_size =
3321     ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
3322   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
3323   vlib_thread_main_t *tm = vlib_get_thread_main ();
3324   vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
3325   {
3326     u16 wk;
3327     u8 tt;
3328     for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3329       {
3330         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3331         vec_validate (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1);
3332         vec_validate (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1);
3333         for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
3334           {
3335             pw->fa_conn_list_head[tt] = ~0;
3336             pw->fa_conn_list_tail[tt] = ~0;
3337           }
3338       }
3339   }
3340
3341   am->fa_min_deleted_sessions_per_interval =
3342     ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
3343   am->fa_max_deleted_sessions_per_interval =
3344     ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
3345   am->fa_cleaner_wait_time_increment =
3346     ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
3347
3348   am->fa_cleaner_cnt_delete_by_sw_index = 0;
3349   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
3350   am->fa_cleaner_cnt_unknown_event = 0;
3351   am->fa_cleaner_cnt_timer_restarted = 0;
3352   am->fa_cleaner_cnt_wait_with_timeout = 0;
3353
3354
3355 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
3356   foreach_acl_eh
3357 #undef _
3358     am->l4_match_nonfirst_fragment = 1;
3359
3360   /* use the new fancy hash-based matching */
3361   am->use_hash_acl_matching = 1;
3362
3363   return error;
3364 }
3365
3366 VLIB_INIT_FUNCTION (acl_init);
3367
3368
3369 /*
3370  * fd.io coding-style-patch-verification: ON
3371  *
3372  * Local Variables:
3373  * eval: (c-set-style "gnu")
3374  * End:
3375  */