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