acl-plugin: don't attempt to delete the ACLs on interface deletion if ACL plugin...
[vpp.git] / src / plugins / acl / acl.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stddef.h>
17
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <acl/acl.h>
21
22 #include <vnet/l2/l2_classify.h>
23 #include <vnet/classify/input_acl.h>
24 #include <vpp/app/version.h>
25
26 #include <vlibapi/api.h>
27 #include <vlibmemory/api.h>
28 #include <vlibsocket/api.h>
29
30 /* define message IDs */
31 #include <acl/acl_msg_enum.h>
32
33 /* define message structures */
34 #define vl_typedefs
35 #include <acl/acl_all_api_h.h>
36 #undef vl_typedefs
37
38 /* define generated endian-swappers */
39 #define vl_endianfun
40 #include <acl/acl_all_api_h.h>
41 #undef vl_endianfun
42
43 /* instantiate all the print functions we know about */
44 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #define vl_printfun
46 #include <acl/acl_all_api_h.h>
47 #undef vl_printfun
48
49 /* Get the API version number */
50 #define vl_api_version(n,v) static u32 api_version=(v);
51 #include <acl/acl_all_api_h.h>
52 #undef vl_api_version
53
54 #include "fa_node.h"
55 #include "hash_lookup.h"
56
57 acl_main_t acl_main;
58
59 #define REPLY_MSG_ID_BASE am->msg_id_base
60 #include <vlibapi/api_helper_macros.h>
61
62 /* List of message types that this plugin understands */
63
64 #define foreach_acl_plugin_api_msg              \
65 _(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \
66 _(ACL_PLUGIN_CONTROL_PING, acl_plugin_control_ping) \
67 _(ACL_ADD_REPLACE, acl_add_replace)                             \
68 _(ACL_DEL, acl_del)                             \
69 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
70 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)       \
71 _(ACL_DUMP, acl_dump)  \
72 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
73 _(MACIP_ACL_ADD, macip_acl_add) \
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 */ , 2 << 29);
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(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(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 = &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 _(x)
322 #define v
323
324 u8 ip4_5tuple_mask[] =
325 _("             dmac               smac            etype ")
326 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
327   _("        v ihl totlen   ")
328   _(0x0000)
329   __ __ __ __
330   _("        ident fl+fo    ")
331   _(0x0004)
332   __ __ __ __
333   _("       ttl pr checksum ")
334   _(0x0008)
335   __ XX __ __
336   _("        src address    ")
337   _(0x000C)
338   XX XX XX XX
339   _("        dst address    ")
340   _(0x0010)
341   XX XX XX XX
342   _("L4 T/U  sport dport    ")
343   _(tcpudp)
344   XX XX XX XX
345   _(padpad)
346   __ __ __ __
347   _(padpad)
348   __ __ __ __
349   _(padeth)
350   __ __;
351
352      u8 ip6_5tuple_mask[] =
353        _("             dmac               smac            etype ")
354   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
355   _("        v  tc + flow ")
356   _(0x0000) __ __ __ __
357   _("        plen  nh hl  ")
358   _(0x0004) __ __ XX __
359   _("        src address  ")
360   _(0x0008) XX XX XX XX
361   _(0x000C) XX XX XX XX
362   _(0x0010) XX XX XX XX
363   _(0x0014) XX XX XX XX
364   _("        dst address  ")
365   _(0x0018) XX XX XX XX
366   _(0x001C) XX XX XX XX
367   _(0x0020) XX XX XX XX
368   _(0x0024) XX XX XX XX
369   _("L4T/U  sport dport   ")
370   _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
371
372 #undef XX
373 #undef __
374 #undef _
375 #undef v
376
377      static int count_skip (u8 * p, u32 size)
378 {
379   u64 *p64 = (u64 *) p;
380   /* Be tolerant to null pointer */
381   if (0 == p)
382     return 0;
383
384   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
385     {
386       p64++;
387     }
388   return (p64 - (u64 *) p) / 2;
389 }
390
391 static int
392 acl_classify_add_del_table_tiny (vnet_classify_main_t * cm, u8 * mask,
393                             u32 mask_len, u32 next_table_index,
394                             u32 miss_next_index, u32 * table_index,
395                             int is_add)
396 {
397   u32 nbuckets = 1;
398   u32 memory_size = 2 << 13;
399   u32 skip = count_skip (mask, mask_len);
400   u32 match = (mask_len / 16) - skip;
401   u8 *skip_mask_ptr = mask + 16 * skip;
402   u32 current_data_flag = 0;
403   int current_data_offset = 0;
404
405   if (0 == match)
406     match = 1;
407   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
408   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
409                                       memory_size, skip, match,
410                                       next_table_index, miss_next_index,
411                                       table_index, current_data_flag,
412                                       current_data_offset, is_add,
413                                       1 /* delete_chain */);
414   clib_mem_set_heap (oldheap);
415   return ret;
416 }
417
418 static int
419 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
420                             u32 mask_len, u32 next_table_index,
421                             u32 miss_next_index, u32 * table_index,
422                             int is_add)
423 {
424   u32 nbuckets = 32;
425   u32 memory_size = 2 << 20;
426   u32 skip = count_skip (mask, mask_len);
427   u32 match = (mask_len / 16) - skip;
428   u8 *skip_mask_ptr = mask + 16 * skip;
429   u32 current_data_flag = 0;
430   int current_data_offset = 0;
431
432   if (0 == match)
433     match = 1;
434
435   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
436   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
437                                       memory_size, skip, match,
438                                       next_table_index, miss_next_index,
439                                       table_index, current_data_flag,
440                                       current_data_offset, is_add,
441                                       1 /* delete_chain */);
442   clib_mem_set_heap (oldheap);
443   return ret;
444 }
445
446
447 static int
448 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
449 {
450   vnet_classify_main_t *cm = &vnet_classify_main;
451   u32 ip4_table_index = ~0;
452   u32 ip6_table_index = ~0;
453   void *oldheap = acl_set_heap(am);
454
455   vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
456                            sw_if_index, ~0);
457   vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
458                            sw_if_index, ~0);
459
460   /* switch to global heap while calling vnet_* functions */
461   clib_mem_set_heap (cm->vlib_main->heap_base);
462   vnet_l2_input_classify_enable_disable (sw_if_index, 0);
463
464   if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
465     {
466       ip4_table_index =
467         am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
468       am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
469       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
470                                   sizeof (ip4_5tuple_mask) - 1, ~0,
471                                   am->l2_input_classify_next_acl_ip4,
472                                   &ip4_table_index, 0);
473     }
474   if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
475     {
476       ip6_table_index =
477         am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
478       am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
479       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
480                                   sizeof (ip6_5tuple_mask) - 1, ~0,
481                                   am->l2_input_classify_next_acl_ip6,
482                                   &ip6_table_index, 0);
483     }
484   clib_mem_set_heap (oldheap);
485   return 0;
486 }
487
488 static int
489 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
490 {
491   vnet_classify_main_t *cm = &vnet_classify_main;
492   u32 ip4_table_index = ~0;
493   u32 ip6_table_index = ~0;
494   void *oldheap = acl_set_heap(am);
495
496   vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
497                            sw_if_index, ~0);
498   vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
499                            sw_if_index, ~0);
500
501   /* switch to global heap while calling vnet_* functions */
502   clib_mem_set_heap (cm->vlib_main->heap_base);
503
504   vnet_l2_output_classify_enable_disable (sw_if_index, 0);
505
506   if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
507     {
508       ip4_table_index =
509         am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
510       am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
511       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
512                                   sizeof (ip4_5tuple_mask) - 1, ~0,
513                                   am->l2_output_classify_next_acl_ip4,
514                                   &ip4_table_index, 0);
515     }
516   if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
517     {
518       ip6_table_index =
519         am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
520       am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
521       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
522                                   sizeof (ip6_5tuple_mask) - 1, ~0,
523                                   am->l2_output_classify_next_acl_ip6,
524                                   &ip6_table_index, 0);
525     }
526   clib_mem_set_heap (oldheap);
527   return 0;
528 }
529
530 static int
531 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
532 {
533   vnet_classify_main_t *cm = &vnet_classify_main;
534   u32 ip4_table_index = ~0;
535   u32 ip6_table_index = ~0;
536   int rv;
537
538   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
539
540   /* in case there were previous tables attached */
541   acl_unhook_l2_input_classify (am, sw_if_index);
542   rv =
543     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
544                                 sizeof (ip4_5tuple_mask) - 1, ~0,
545                                 am->l2_input_classify_next_acl_ip4,
546                                 &ip4_table_index, 1);
547   if (rv)
548     goto done;
549   rv =
550     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
551                                 sizeof (ip6_5tuple_mask) - 1, ~0,
552                                 am->l2_input_classify_next_acl_ip6,
553                                 &ip6_table_index, 1);
554   if (rv)
555     {
556       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
557                                   sizeof (ip4_5tuple_mask) - 1, ~0,
558                                   am->l2_input_classify_next_acl_ip4,
559                                   &ip4_table_index, 0);
560       goto done;
561     }
562   rv =
563     vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
564                                        ip6_table_index, ~0);
565   clib_warning
566     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
567      sw_if_index, ip4_table_index, ip6_table_index);
568   if (rv)
569     {
570       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
571                                   sizeof (ip6_5tuple_mask) - 1, ~0,
572                                   am->l2_input_classify_next_acl_ip6,
573                                   &ip6_table_index, 0);
574       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
575                                   sizeof (ip4_5tuple_mask) - 1, ~0,
576                                   am->l2_input_classify_next_acl_ip4,
577                                   &ip4_table_index, 0);
578       goto done;
579     }
580
581   am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
582     ip4_table_index;
583   am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
584     ip6_table_index;
585
586   vnet_l2_input_classify_enable_disable (sw_if_index, 1);
587 done:
588   clib_mem_set_heap (prevheap);
589   return rv;
590 }
591
592 static int
593 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
594 {
595   vnet_classify_main_t *cm = &vnet_classify_main;
596   u32 ip4_table_index = ~0;
597   u32 ip6_table_index = ~0;
598   int rv;
599
600   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
601
602   /* in case there were previous tables attached */
603   acl_unhook_l2_output_classify (am, sw_if_index);
604   rv =
605     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
606                                 sizeof (ip4_5tuple_mask) - 1, ~0,
607                                 am->l2_output_classify_next_acl_ip4,
608                                 &ip4_table_index, 1);
609   if (rv)
610     goto done;
611   rv =
612     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
613                                 sizeof (ip6_5tuple_mask) - 1, ~0,
614                                 am->l2_output_classify_next_acl_ip6,
615                                 &ip6_table_index, 1);
616   if (rv)
617     {
618       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
619                                   sizeof (ip4_5tuple_mask) - 1, ~0,
620                                   am->l2_output_classify_next_acl_ip4,
621                                   &ip4_table_index, 0);
622       goto done;
623     }
624   rv =
625     vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
626                                         ip6_table_index, ~0);
627   clib_warning
628     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
629      sw_if_index, ip4_table_index, ip6_table_index);
630   if (rv)
631     {
632       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
633                                   sizeof (ip6_5tuple_mask) - 1, ~0,
634                                   am->l2_output_classify_next_acl_ip6,
635                                   &ip6_table_index, 0);
636       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
637                                   sizeof (ip4_5tuple_mask) - 1, ~0,
638                                   am->l2_output_classify_next_acl_ip4,
639                                   &ip4_table_index, 0);
640       goto done;
641     }
642
643   am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
644     ip4_table_index;
645   am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
646     ip6_table_index;
647
648   vnet_l2_output_classify_enable_disable (sw_if_index, 1);
649 done:
650   clib_mem_set_heap (prevheap);
651   return rv;
652 }
653
654
655
656 int
657 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
658                                  int enable_disable)
659 {
660   int rv;
661
662   /* Utterly wrong? */
663   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
664                           sw_if_index))
665     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
666
667   acl_fa_enable_disable(sw_if_index, 1, enable_disable);
668
669   if (enable_disable)
670     {
671       rv = acl_hook_l2_input_classify (am, sw_if_index);
672     }
673   else
674     {
675       rv = acl_unhook_l2_input_classify (am, sw_if_index);
676     }
677
678   return rv;
679 }
680
681 int
682 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
683                                   int enable_disable)
684 {
685   int rv;
686
687   /* Utterly wrong? */
688   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
689                           sw_if_index))
690     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
691
692   acl_fa_enable_disable(sw_if_index, 0, enable_disable);
693
694   if (enable_disable)
695     {
696       rv = acl_hook_l2_output_classify (am, sw_if_index);
697     }
698   else
699     {
700       rv = acl_unhook_l2_output_classify (am, sw_if_index);
701     }
702
703   return rv;
704 }
705
706 static int
707 acl_is_not_defined(acl_main_t *am, u32 acl_list_index)
708 {
709   return (pool_is_free_index (am->acls, acl_list_index));
710 }
711
712
713 static int
714 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
715 {
716   acl_main_t *am = &acl_main;
717   if (acl_is_not_defined(am, acl_list_index)) {
718     /* ACL is not defined. Can not apply */
719     return -1;
720   }
721   void *oldheap = acl_set_heap(am);
722
723   if (is_input)
724     {
725       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
726
727       u32 index = vec_search(am->input_acl_vec_by_sw_if_index[sw_if_index], acl_list_index);
728       if (index < vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index])) {
729         clib_warning("ACL %d is already applied inbound on sw_if_index %d (index %d)",
730                      acl_list_index, sw_if_index, index);
731         /* the entry is already there */
732         clib_mem_set_heap (oldheap);
733         return -1;
734       }
735       /* if there was no ACL applied before, enable the ACL processing */
736       if (vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index]) == 0) {
737         acl_interface_in_enable_disable (am, sw_if_index, 1);
738       }
739       vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
740                1);
741       vec_validate (am->input_sw_if_index_vec_by_acl, acl_list_index);
742       vec_add (am->input_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
743                1);
744     }
745   else
746     {
747       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
748
749       u32 index = vec_search(am->output_acl_vec_by_sw_if_index[sw_if_index], acl_list_index);
750       if (index < vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index])) {
751         clib_warning("ACL %d is already applied outbound on sw_if_index %d (index %d)",
752                      acl_list_index, sw_if_index, index);
753         /* the entry is already there */
754         clib_mem_set_heap (oldheap);
755         return -1;
756       }
757       /* if there was no ACL applied before, enable the ACL processing */
758       if (vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index]) == 0) {
759         acl_interface_out_enable_disable (am, sw_if_index, 1);
760       }
761       vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
762                &acl_list_index, 1);
763       vec_validate (am->output_sw_if_index_vec_by_acl, acl_list_index);
764       vec_add (am->output_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
765                1);
766     }
767   clib_mem_set_heap (oldheap);
768   return 0;
769 }
770
771
772 static int
773 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
774 {
775   acl_main_t *am = &acl_main;
776   int i;
777   int rv = -1;
778   void *oldheap = acl_set_heap(am);
779   if (is_input)
780     {
781       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
782       for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
783            i++)
784         {
785           if (acl_list_index ==
786               am->input_acl_vec_by_sw_if_index[sw_if_index][i])
787             {
788               vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
789               rv = 0;
790               break;
791             }
792         }
793
794       if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
795         u32 index = vec_search(am->input_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
796         if (index < vec_len(am->input_sw_if_index_vec_by_acl[acl_list_index])) {
797           hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
798           vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index], index);
799         }
800       }
801
802       /* If there is no more ACLs applied on an interface, disable ACL processing */
803       if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
804         {
805           acl_interface_in_enable_disable (am, sw_if_index, 0);
806         }
807     }
808   else
809     {
810       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
811       for (i = 0;
812            i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
813         {
814           if (acl_list_index ==
815               am->output_acl_vec_by_sw_if_index[sw_if_index][i])
816             {
817               vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
818               rv = 0;
819               break;
820             }
821         }
822
823       if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
824         u32 index = vec_search(am->output_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
825         if (index < vec_len(am->output_sw_if_index_vec_by_acl[acl_list_index])) {
826           hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
827           vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index], index);
828         }
829       }
830
831       /* If there is no more ACLs applied on an interface, disable ACL processing */
832       if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
833         {
834           acl_interface_out_enable_disable (am, sw_if_index, 0);
835         }
836     }
837   clib_mem_set_heap (oldheap);
838   return rv;
839 }
840
841 static void
842 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
843 {
844   acl_main_t *am = &acl_main;
845   int i;
846   void *oldheap = acl_set_heap(am);
847   if (is_input)
848     {
849       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
850       if (vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0) {
851         acl_interface_in_enable_disable (am, sw_if_index, 0);
852       }
853
854       for(i = vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index])-1; i>=0; i--) {
855         u32 acl_list_index = am->input_acl_vec_by_sw_if_index[sw_if_index][i];
856         hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
857         if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
858           u32 index = vec_search(am->input_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
859           if (index < vec_len(am->input_sw_if_index_vec_by_acl[acl_list_index])) {
860             vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index], index);
861           }
862         }
863       }
864
865       vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
866     }
867   else
868     {
869       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
870       if (vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0) {
871         acl_interface_out_enable_disable (am, sw_if_index, 0);
872       }
873
874       for(i = vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index])-1; i>=0; i--) {
875         u32 acl_list_index = am->output_acl_vec_by_sw_if_index[sw_if_index][i];
876         hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
877         if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
878           u32 index = vec_search(am->output_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
879           if (index < vec_len(am->output_sw_if_index_vec_by_acl[acl_list_index])) {
880             vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index], index);
881           }
882         }
883       }
884
885       vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
886     }
887   clib_mem_set_heap (oldheap);
888 }
889
890 static int
891 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
892                                  u32 acl_list_index)
893 {
894   int rv = -1;
895   acl_main_t *am = &acl_main;
896   void *oldheap = acl_set_heap(am);
897   if (is_add)
898     {
899       rv =
900         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
901       if (rv == 0)
902         {
903           hash_acl_apply(am, sw_if_index, is_input, acl_list_index);
904         }
905     }
906   else
907     {
908       hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
909       rv =
910         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
911     }
912   clib_mem_set_heap (oldheap);
913   return rv;
914 }
915
916
917 typedef struct
918 {
919   u8 is_ipv6;
920   u8 mac_mask[6];
921   u8 prefix_len;
922   u32 count;
923   u32 table_index;
924   u32 arp_table_index;
925 } macip_match_type_t;
926
927 static u32
928 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
929                        u8 is_ipv6)
930 {
931   u32 i;
932   if (mv)
933     {
934       for (i = 0; i < vec_len (mv); i++)
935         {
936           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
937               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
938             {
939               return i;
940             }
941         }
942     }
943   return ~0;
944 }
945
946
947 /* Get metric used to sort match types.
948    The more specific and the more often seen - the bigger the metric */
949 static int
950 match_type_metric (macip_match_type_t * m)
951 {
952   /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */
953   return m->prefix_len + m->is_ipv6 + 10 * m->count;
954 }
955
956 static int
957 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
958 {
959   /* Ascending sort based on the metric values */
960   return match_type_metric (m1) - match_type_metric (m2);
961 }
962
963 /* Get the offset of L3 source within ethernet packet */
964 static int
965 get_l3_src_offset(int is6)
966 {
967   if(is6)
968     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
969   else
970     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
971 }
972
973 static int
974 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
975 {
976   macip_match_type_t *mvec = NULL;
977   macip_match_type_t *mt;
978   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
979   int i;
980   u32 match_type_index;
981   u32 last_table;
982   u8 mask[5 * 16];
983   vnet_classify_main_t *cm = &vnet_classify_main;
984
985   /* Count the number of different types of rules */
986   for (i = 0; i < a->count; i++)
987     {
988       if (~0 ==
989           (match_type_index =
990            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
991                                   a->rules[i].src_prefixlen,
992                                   a->rules[i].is_ipv6)))
993         {
994           match_type_index = vec_len (mvec);
995           vec_validate (mvec, match_type_index);
996           memcpy (mvec[match_type_index].mac_mask,
997                   a->rules[match_type_index].src_mac_mask, 6);
998           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
999           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1000           mvec[match_type_index].table_index = ~0;
1001         }
1002       mvec[match_type_index].count++;
1003     }
1004   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1005   vec_sort_with_function (mvec, match_type_compare);
1006   /* Create the classifier tables */
1007   last_table = ~0;
1008   /* First add ARP tables */
1009   vec_foreach (mt, mvec)
1010   {
1011     int mask_len;
1012     int is6 = mt->is_ipv6;
1013
1014     mt->arp_table_index = ~0;
1015     if (!is6)
1016       {
1017         memset (mask, 0, sizeof (mask));
1018         memcpy (&mask[6], mt->mac_mask, 6);
1019         memset (&mask[12], 0xff, 2); /* ethernet protocol */
1020         memcpy (&mask[14 + 8], mt->mac_mask, 6);
1021
1022         for (i = 0; i < (mt->prefix_len / 8); i++)
1023           mask[14 + 14 + i] = 0xff;
1024         if (mt->prefix_len % 8)
1025           mask[14 + 14 + (mt->prefix_len / 8)] = 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1026
1027         mask_len = ((14 + 14 + ((mt->prefix_len+7) / 8) +
1028                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1029         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1030                                (~0 == last_table) ? 0 : ~0, &mt->arp_table_index,
1031                                1);
1032         last_table = mt->arp_table_index;
1033       }
1034   }
1035   /* Now add IP[46] tables */
1036   vec_foreach (mt, mvec)
1037   {
1038     int mask_len;
1039     int is6 = mt->is_ipv6;
1040     int l3_src_offs = get_l3_src_offset(is6);
1041     memset (mask, 0, sizeof (mask));
1042     memcpy (&mask[6], mt->mac_mask, 6);
1043     for (i = 0; i < (mt->prefix_len / 8); i++)
1044       {
1045         mask[l3_src_offs + i] = 0xff;
1046       }
1047     if (mt->prefix_len % 8)
1048       {
1049         mask[l3_src_offs + (mt->prefix_len / 8)] =
1050           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1051       }
1052     /*
1053      * Round-up the number of bytes needed to store the prefix,
1054      * and round up the number of vectors too
1055      */
1056     mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) +
1057                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1058     acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1059                                 (~0 == last_table) ? 0 : ~0, &mt->table_index,
1060                                 1);
1061     last_table = mt->table_index;
1062   }
1063   a->ip4_table_index = ~0;
1064   a->ip6_table_index = ~0;
1065   a->l2_table_index = last_table;
1066
1067   /* Populate the classifier tables with rules from the MACIP ACL */
1068   for (i = 0; i < a->count; i++)
1069     {
1070       u32 action = 0;
1071       u32 metadata = 0;
1072       int is6 = a->rules[i].is_ipv6;
1073       int l3_src_offs = get_l3_src_offset(is6);
1074       memset (mask, 0, sizeof (mask));
1075       memcpy (&mask[6], a->rules[i].src_mac, 6);
1076       memset (&mask[12], 0xff, 2); /* ethernet protocol */
1077       if (is6)
1078         {
1079           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1080           mask[12] = 0x86;
1081           mask[13] = 0xdd;
1082         }
1083       else
1084         {
1085           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1086           mask[12] = 0x08;
1087           mask[13] = 0x00;
1088         }
1089       match_type_index =
1090         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1091                                a->rules[i].src_prefixlen,
1092                                a->rules[i].is_ipv6);
1093       ASSERT(match_type_index != ~0);
1094       /* add session to table mvec[match_type_index].table_index; */
1095       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
1096                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
1097                                      0, action, metadata, 1);
1098       /* add ARP table entry too */
1099       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1100         {
1101           memset (mask, 0, sizeof (mask));
1102           memcpy (&mask[6], a->rules[i].src_mac, 6);
1103           mask[12] = 0x08;
1104           mask[13] = 0x06;
1105           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
1106           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
1107           vnet_classify_add_del_session (cm, mvec[match_type_index].arp_table_index,
1108                                     mask, a->rules[i].is_permit ? ~0 : 0, i,
1109                                     0, action, metadata, 1);
1110         }
1111     }
1112   return 0;
1113 }
1114
1115 static void
1116 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1117 {
1118   vnet_classify_main_t *cm = &vnet_classify_main;
1119   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
1120
1121   if (a->ip4_table_index != ~0)
1122     {
1123       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
1124       a->ip4_table_index = ~0;
1125     }
1126   if (a->ip6_table_index != ~0)
1127     {
1128       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
1129       a->ip6_table_index = ~0;
1130     }
1131   if (a->l2_table_index != ~0)
1132     {
1133       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
1134       a->l2_table_index = ~0;
1135     }
1136 }
1137
1138 static int
1139 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1140                     u32 * acl_list_index, u8 * tag)
1141 {
1142   acl_main_t *am = &acl_main;
1143   macip_acl_list_t *a;
1144   macip_acl_rule_t *r;
1145   macip_acl_rule_t *acl_new_rules = 0;
1146   int i;
1147   if (0 == count) {
1148     clib_warning("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)", tag);
1149   }
1150   void *oldheap = acl_set_heap(am);
1151   /* Create and populate the rules */
1152   if (count > 0)
1153     vec_validate(acl_new_rules, count-1);
1154
1155   for (i = 0; i < count; i++)
1156     {
1157       r = &acl_new_rules[i];
1158       r->is_permit = rules[i].is_permit;
1159       r->is_ipv6 = rules[i].is_ipv6;
1160       memcpy (&r->src_mac, rules[i].src_mac, 6);
1161       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1162       if(rules[i].is_ipv6)
1163         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1164       else
1165         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1166       r->src_prefixlen = rules[i].src_ip_prefix_len;
1167     }
1168
1169   /* Get ACL index */
1170   pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1171   memset (a, 0, sizeof (*a));
1172   /* Will return the newly allocated ACL index */
1173   *acl_list_index = a - am->macip_acls;
1174
1175   a->rules = acl_new_rules;
1176   a->count = count;
1177   memcpy (a->tag, tag, sizeof (a->tag));
1178
1179   /* Create and populate the classifer tables */
1180   macip_create_classify_tables (am, *acl_list_index);
1181   clib_mem_set_heap (oldheap);
1182   return 0;
1183 }
1184
1185
1186 /* No check for validity of sw_if_index - the callers were supposed to validate */
1187
1188 static int
1189 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1190 {
1191   int rv;
1192   u32 macip_acl_index;
1193   macip_acl_list_t *a;
1194   void *oldheap = acl_set_heap(am);
1195   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1196   clib_mem_set_heap (oldheap);
1197   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1198   /* No point in deleting MACIP ACL which is not applied */
1199   if (~0 == macip_acl_index)
1200     return -1;
1201   a = &am->macip_acls[macip_acl_index];
1202   /* remove the classifier tables off the interface L2 ACL */
1203   rv =
1204     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1205                               a->ip6_table_index, a->l2_table_index, 0);
1206   /* Unset the MACIP ACL index */
1207   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1208   return rv;
1209 }
1210
1211 /* No check for validity of sw_if_index - the callers were supposed to validate */
1212
1213 static int
1214 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1215                              u32 macip_acl_index)
1216 {
1217   macip_acl_list_t *a;
1218   int rv;
1219   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1220     {
1221       return -1;
1222     }
1223   void *oldheap = acl_set_heap(am);
1224   a = &am->macip_acls[macip_acl_index];
1225   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1226   /* If there already a MACIP ACL applied, unapply it */
1227   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1228     macip_acl_interface_del_acl(am, sw_if_index);
1229   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1230   clib_mem_set_heap (oldheap);
1231
1232   /* Apply the classifier tables for L2 ACLs */
1233   rv =
1234     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1235                               a->ip6_table_index, a->l2_table_index, 1);
1236   return rv;
1237 }
1238
1239 static int
1240 macip_acl_del_list (u32 acl_list_index)
1241 {
1242   acl_main_t *am = &acl_main;
1243   void *oldheap = acl_set_heap(am);
1244   macip_acl_list_t *a;
1245   int i;
1246   if (pool_is_free_index (am->macip_acls, acl_list_index))
1247     {
1248       return -1;
1249     }
1250
1251   /* delete any references to the ACL */
1252   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1253     {
1254       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1255         {
1256           macip_acl_interface_del_acl (am, i);
1257         }
1258     }
1259
1260   /* Now that classifier tables are detached, clean them up */
1261   macip_destroy_classify_tables (am, acl_list_index);
1262
1263   /* now we can delete the ACL itself */
1264   a = &am->macip_acls[acl_list_index];
1265   if (a->rules)
1266     {
1267       vec_free (a->rules);
1268     }
1269   pool_put (am->macip_acls, a);
1270   clib_mem_set_heap (oldheap);
1271   return 0;
1272 }
1273
1274
1275 static int
1276 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1277                                  u32 acl_list_index)
1278 {
1279   acl_main_t *am = &acl_main;
1280   void *oldheap = acl_set_heap(am);
1281   int rv = -1;
1282   if (is_add)
1283     {
1284       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1285     }
1286   else
1287     {
1288       rv = macip_acl_interface_del_acl (am, sw_if_index);
1289     }
1290   clib_mem_set_heap (oldheap);
1291   return rv;
1292 }
1293
1294 /*
1295  * If the client does not allocate enough memory for a variable-length
1296  * message, and then proceed to use it as if the full memory allocated,
1297  * absent the check we happily consume that on the VPP side, and go
1298  * along as if nothing happened. However, the resulting
1299  * effects range from just garbage in the API decode
1300  * (because the decoder snoops too far), to potential memory
1301  * corruptions.
1302  *
1303  * This verifies that the actual length of the message is
1304  * at least expected_len, and complains loudly if it is not.
1305  *
1306  * A failing check here is 100% a software bug on the API user side,
1307  * so we might as well yell.
1308  *
1309  */
1310 static int verify_message_len(void *mp, u32 expected_len, char *where)
1311 {
1312   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1313   if (supplied_len < expected_len) {
1314       clib_warning("%s: Supplied message length %d is less than expected %d",
1315                    where, supplied_len, expected_len);
1316       return 0;
1317   } else {
1318       return 1;
1319   }
1320 }
1321
1322 /* API message handler */
1323 static void
1324 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1325 {
1326   vl_api_acl_add_replace_reply_t *rmp;
1327   acl_main_t *am = &acl_main;
1328   int rv;
1329   u32 acl_list_index = ntohl (mp->acl_index);
1330   u32 acl_count = ntohl (mp->count);
1331   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1332
1333   if (verify_message_len(mp, expected_len, "acl_add_replace")) {
1334       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1335   } else {
1336       rv = VNET_API_ERROR_INVALID_VALUE;
1337   }
1338
1339   /* *INDENT-OFF* */
1340   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1341   ({
1342     rmp->acl_index = htonl(acl_list_index);
1343   }));
1344   /* *INDENT-ON* */
1345 }
1346
1347 static void
1348 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1349 {
1350   acl_main_t *am = &acl_main;
1351   vl_api_acl_del_reply_t *rmp;
1352   int rv;
1353
1354   rv = acl_del_list (ntohl (mp->acl_index));
1355
1356   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1357 }
1358
1359 static void
1360 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1361 {
1362   acl_main_t *am = &acl_main;
1363   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1364   u32 sw_if_index = ntohl (mp->sw_if_index);
1365   vl_api_acl_interface_add_del_reply_t *rmp;
1366   int rv = -1;
1367
1368   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1369     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1370   else
1371     rv =
1372       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1373                                      mp->is_input, ntohl (mp->acl_index));
1374
1375   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1376 }
1377
1378 static void
1379 vl_api_acl_interface_set_acl_list_t_handler
1380   (vl_api_acl_interface_set_acl_list_t * mp)
1381 {
1382   acl_main_t *am = &acl_main;
1383   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1384   int rv = 0;
1385   int i;
1386   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1387   u32 sw_if_index = ntohl (mp->sw_if_index);
1388
1389   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1390     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1391   else
1392     {
1393       acl_interface_reset_inout_acls (sw_if_index, 0);
1394       acl_interface_reset_inout_acls (sw_if_index, 1);
1395
1396       for (i = 0; i < mp->count; i++)
1397         {
1398           if(acl_is_not_defined(am, ntohl (mp->acls[i]))) {
1399             /* ACL does not exist, so we can not apply it */
1400             rv = -1;
1401           }
1402         }
1403       if (0 == rv) {
1404         for (i = 0; i < mp->count; i++)
1405           {
1406             acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1407                                        ntohl (mp->acls[i]));
1408           }
1409       }
1410     }
1411
1412   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1413 }
1414
1415 static void
1416 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1417 {
1418   api_rule->is_permit = r->is_permit;
1419   api_rule->is_ipv6 = r->is_ipv6;
1420   if(r->is_ipv6)
1421     {
1422       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1423       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1424     }
1425   else
1426     {
1427       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1428       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1429     }
1430   api_rule->src_ip_prefix_len = r->src_prefixlen;
1431   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1432   api_rule->proto = r->proto;
1433   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1434   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1435   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1436   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1437   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1438   api_rule->tcp_flags_value = r->tcp_flags_value;
1439 }
1440
1441 static void
1442 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1443                   acl_list_t * acl, u32 context)
1444 {
1445   vl_api_acl_details_t *mp;
1446   vl_api_acl_rule_t *rules;
1447   int i;
1448   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1449   void *oldheap = acl_set_heap(am);
1450
1451   mp = vl_msg_api_alloc (msg_size);
1452   memset (mp, 0, msg_size);
1453   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1454
1455   /* fill in the message */
1456   mp->context = context;
1457   mp->count = htonl (acl->count);
1458   mp->acl_index = htonl (acl - am->acls);
1459   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1460   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1461   rules = mp->r;
1462   for (i = 0; i < acl->count; i++)
1463     {
1464       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1465     }
1466
1467   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1468   clib_mem_set_heap (oldheap);
1469   vl_msg_api_send_shmem (q, (u8 *) & mp);
1470 }
1471
1472
1473 static void
1474 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1475 {
1476   acl_main_t *am = &acl_main;
1477   u32 acl_index;
1478   acl_list_t *acl;
1479
1480   int rv = -1;
1481   unix_shared_memory_queue_t *q;
1482
1483   q = vl_api_client_index_to_input_queue (mp->client_index);
1484   if (q == 0)
1485     {
1486       return;
1487     }
1488
1489   if (mp->acl_index == ~0)
1490     {
1491     /* *INDENT-OFF* */
1492     /* Just dump all ACLs */
1493     pool_foreach (acl, am->acls,
1494     ({
1495       send_acl_details(am, q, acl, mp->context);
1496     }));
1497     /* *INDENT-ON* */
1498     }
1499   else
1500     {
1501       acl_index = ntohl (mp->acl_index);
1502       if (!pool_is_free_index (am->acls, acl_index))
1503         {
1504           acl = &am->acls[acl_index];
1505           send_acl_details (am, q, acl, mp->context);
1506         }
1507     }
1508
1509   if (rv == -1)
1510     {
1511       /* FIXME API: should we signal an error here at all ? */
1512       return;
1513     }
1514 }
1515
1516 static void
1517 send_acl_interface_list_details (acl_main_t * am,
1518                                  unix_shared_memory_queue_t * q,
1519                                  u32 sw_if_index, u32 context)
1520 {
1521   vl_api_acl_interface_list_details_t *mp;
1522   int msg_size;
1523   int n_input;
1524   int n_output;
1525   int count;
1526   int i = 0;
1527   void *oldheap = acl_set_heap(am);
1528
1529   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1530   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1531
1532   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1533   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1534   count = n_input + n_output;
1535
1536   msg_size = sizeof (*mp);
1537   msg_size += sizeof (mp->acls[0]) * count;
1538
1539   mp = vl_msg_api_alloc (msg_size);
1540   memset (mp, 0, msg_size);
1541   mp->_vl_msg_id =
1542     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1543
1544   /* fill in the message */
1545   mp->context = context;
1546   mp->sw_if_index = htonl (sw_if_index);
1547   mp->count = count;
1548   mp->n_input = n_input;
1549   for (i = 0; i < n_input; i++)
1550     {
1551       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1552     }
1553   for (i = 0; i < n_output; i++)
1554     {
1555       mp->acls[n_input + i] =
1556         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1557     }
1558   clib_mem_set_heap (oldheap);
1559   vl_msg_api_send_shmem (q, (u8 *) & mp);
1560 }
1561
1562 static void
1563 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1564                                           mp)
1565 {
1566   acl_main_t *am = &acl_main;
1567   vnet_sw_interface_t *swif;
1568   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1569
1570   u32 sw_if_index;
1571   unix_shared_memory_queue_t *q;
1572
1573   q = vl_api_client_index_to_input_queue (mp->client_index);
1574   if (q == 0)
1575     {
1576       return;
1577     }
1578
1579   if (mp->sw_if_index == ~0)
1580     {
1581     /* *INDENT-OFF* */
1582     pool_foreach (swif, im->sw_interfaces,
1583     ({
1584       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1585     }));
1586     /* *INDENT-ON* */
1587     }
1588   else
1589     {
1590       sw_if_index = ntohl (mp->sw_if_index);
1591       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1592         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1593     }
1594 }
1595
1596 /* MACIP ACL API handlers */
1597
1598 static void
1599 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1600 {
1601   vl_api_macip_acl_add_reply_t *rmp;
1602   acl_main_t *am = &acl_main;
1603   int rv;
1604   u32 acl_list_index = ~0;
1605   u32 acl_count = ntohl (mp->count);
1606   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1607
1608   if (verify_message_len(mp, expected_len, "macip_acl_add")) {
1609       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1610   } else {
1611       rv = VNET_API_ERROR_INVALID_VALUE;
1612   }
1613
1614   /* *INDENT-OFF* */
1615   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1616   ({
1617     rmp->acl_index = htonl(acl_list_index);
1618   }));
1619   /* *INDENT-ON* */
1620 }
1621
1622 static void
1623 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1624 {
1625   acl_main_t *am = &acl_main;
1626   vl_api_macip_acl_del_reply_t *rmp;
1627   int rv;
1628
1629   rv = macip_acl_del_list (ntohl (mp->acl_index));
1630
1631   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1632 }
1633
1634 static void
1635 vl_api_macip_acl_interface_add_del_t_handler
1636   (vl_api_macip_acl_interface_add_del_t * mp)
1637 {
1638   acl_main_t *am = &acl_main;
1639   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1640   int rv = -1;
1641   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1642   u32 sw_if_index = ntohl (mp->sw_if_index);
1643
1644   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1645     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1646   else
1647     rv =
1648       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1649                                      ntohl (mp->acl_index));
1650
1651   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1652 }
1653
1654 static void
1655 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1656                         macip_acl_list_t * acl, u32 context)
1657 {
1658   vl_api_macip_acl_details_t *mp;
1659   vl_api_macip_acl_rule_t *rules;
1660   macip_acl_rule_t *r;
1661   int i;
1662   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1663
1664   mp = vl_msg_api_alloc (msg_size);
1665   memset (mp, 0, msg_size);
1666   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1667
1668   /* fill in the message */
1669   mp->context = context;
1670   if (acl)
1671     {
1672       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1673       mp->count = htonl (acl->count);
1674       mp->acl_index = htonl (acl - am->macip_acls);
1675       rules = mp->r;
1676       for (i = 0; i < acl->count; i++)
1677         {
1678           r = &acl->rules[i];
1679           rules[i].is_permit = r->is_permit;
1680           rules[i].is_ipv6 = r->is_ipv6;
1681           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1682           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1683                   sizeof (r->src_mac_mask));
1684           if (r->is_ipv6)
1685             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1686                   sizeof (r->src_ip_addr.ip6));
1687           else
1688             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1689                   sizeof (r->src_ip_addr.ip4));
1690           rules[i].src_ip_prefix_len = r->src_prefixlen;
1691         }
1692     }
1693   else
1694     {
1695       /* No martini, no party - no ACL applied to this interface. */
1696       mp->acl_index = ~0;
1697       mp->count = 0;
1698     }
1699
1700   vl_msg_api_send_shmem (q, (u8 *) & mp);
1701 }
1702
1703
1704 static void
1705 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1706 {
1707   acl_main_t *am = &acl_main;
1708   macip_acl_list_t *acl;
1709
1710   unix_shared_memory_queue_t *q;
1711
1712   q = vl_api_client_index_to_input_queue (mp->client_index);
1713   if (q == 0)
1714     {
1715       return;
1716     }
1717
1718   if (mp->acl_index == ~0)
1719     {
1720       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1721       pool_foreach (acl, am->macip_acls, (
1722                                            {
1723                                            send_macip_acl_details (am, q, acl,
1724                                                                    mp->
1725                                                                    context);}
1726                     ));
1727       /* *INDENT-ON* */
1728     }
1729   else
1730     {
1731       u32 acl_index = ntohl (mp->acl_index);
1732       if (!pool_is_free_index (am->macip_acls, acl_index))
1733         {
1734           acl = &am->macip_acls[acl_index];
1735           send_macip_acl_details (am, q, acl, mp->context);
1736         }
1737     }
1738 }
1739
1740 static void
1741 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1742                                           mp)
1743 {
1744   acl_main_t *am = &acl_main;
1745   vl_api_macip_acl_interface_get_reply_t *rmp;
1746   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1747   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1748   unix_shared_memory_queue_t *q;
1749   int i;
1750
1751   q = vl_api_client_index_to_input_queue (mp->client_index);
1752   if (q == 0)
1753     {
1754       return;
1755     }
1756
1757   rmp = vl_msg_api_alloc (msg_size);
1758   memset (rmp, 0, msg_size);
1759   rmp->_vl_msg_id =
1760     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1761   rmp->context = mp->context;
1762   rmp->count = htonl (count);
1763   for (i = 0; i < count; i++)
1764     {
1765       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1766     }
1767
1768   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1769 }
1770
1771 static void
1772 send_macip_acl_interface_list_details (acl_main_t * am,
1773                                        unix_shared_memory_queue_t * q,
1774                                        u32 sw_if_index,
1775                                        u32 acl_index,
1776                                        u32 context)
1777 {
1778   vl_api_macip_acl_interface_list_details_t *rmp;
1779   /* at this time there is only ever 1 mac ip acl per interface */
1780   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
1781
1782   rmp = vl_msg_api_alloc (msg_size);
1783   memset (rmp, 0, msg_size);
1784   rmp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1785
1786   /* fill in the message */
1787   rmp->context = context;
1788   rmp->count = 1;
1789   rmp->sw_if_index = htonl (sw_if_index);
1790   rmp->acls[0] = htonl (acl_index);
1791
1792   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1793 }
1794
1795 static void
1796 vl_api_macip_acl_interface_list_dump_t_handler (vl_api_macip_acl_interface_list_dump_t *mp)
1797 {
1798   unix_shared_memory_queue_t *q;
1799   acl_main_t *am = &acl_main;
1800   u32 sw_if_index = ntohl (mp->sw_if_index);
1801
1802   q = vl_api_client_index_to_input_queue (mp->client_index);
1803   if (q == 0)
1804     {
1805       return;
1806     }
1807
1808   if (sw_if_index == ~0)
1809     {
1810       vec_foreach_index(sw_if_index, am->macip_acl_by_sw_if_index)
1811         {
1812           if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1813             {
1814               send_macip_acl_interface_list_details(am, q,  sw_if_index,
1815                                                     am->macip_acl_by_sw_if_index[sw_if_index],
1816                                                     mp->context);
1817             }
1818         }
1819     }
1820   else
1821     {
1822       if (vec_len(am->macip_acl_by_sw_if_index) > sw_if_index)
1823         {
1824           send_macip_acl_interface_list_details(am, q, sw_if_index,
1825                                                 am->macip_acl_by_sw_if_index[sw_if_index],
1826                                                 mp->context);
1827         }
1828     }
1829 }
1830
1831 /* Set up the API message handling tables */
1832 static clib_error_t *
1833 acl_plugin_api_hookup (vlib_main_t * vm)
1834 {
1835   acl_main_t *am = &acl_main;
1836 #define _(N,n)                                                  \
1837     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
1838                            #n,                                  \
1839                            vl_api_##n##_t_handler,              \
1840                            vl_noop_handler,                     \
1841                            vl_api_##n##_t_endian,               \
1842                            vl_api_##n##_t_print,                \
1843                            sizeof(vl_api_##n##_t), 1);
1844   foreach_acl_plugin_api_msg;
1845 #undef _
1846
1847   return 0;
1848 }
1849
1850 #define vl_msg_name_crc_list
1851 #include <acl/acl_all_api_h.h>
1852 #undef vl_msg_name_crc_list
1853
1854 static void
1855 setup_message_id_table (acl_main_t * am, api_main_t * apim)
1856 {
1857 #define _(id,n,crc) \
1858   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
1859   foreach_vl_msg_name_crc_acl;
1860 #undef _
1861 }
1862
1863 static void
1864 acl_setup_fa_nodes (void)
1865 {
1866   vlib_main_t *vm = vlib_get_main ();
1867   acl_main_t *am = &acl_main;
1868   vlib_node_t *n, *n4, *n6;
1869
1870   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1871   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
1872   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
1873
1874
1875   am->l2_input_classify_next_acl_ip4 =
1876     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1877   am->l2_input_classify_next_acl_ip6 =
1878     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1879
1880   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
1881                                l2input_get_feat_names (),
1882                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
1883
1884   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
1885                                l2input_get_feat_names (),
1886                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
1887
1888
1889   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1890   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
1891   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
1892
1893   am->l2_output_classify_next_acl_ip4 =
1894     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1895   am->l2_output_classify_next_acl_ip6 =
1896     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1897
1898   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
1899                                l2output_get_feat_names (),
1900                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
1901
1902   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
1903                                l2output_get_feat_names (),
1904                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
1905 }
1906
1907 static void
1908 acl_set_timeout_sec(int timeout_type, u32 value)
1909 {
1910   acl_main_t *am = &acl_main;
1911   clib_time_t *ct = &am->vlib_main->clib_time;
1912
1913   if (timeout_type < ACL_N_TIMEOUTS) {
1914     am->session_timeout_sec[timeout_type] = value;
1915   } else {
1916     clib_warning("Unknown timeout type %d", timeout_type);
1917     return;
1918   }
1919   am->session_timeout[timeout_type] = (u64)(((f64)value)/ct->seconds_per_clock);
1920 }
1921
1922 static void
1923 acl_set_session_max_entries(u32 value)
1924 {
1925   acl_main_t *am = &acl_main;
1926   am->fa_conn_table_max_entries = value;
1927 }
1928
1929 static int
1930 acl_set_skip_ipv6_eh(u32 eh, u32 value)
1931 {
1932   acl_main_t *am = &acl_main;
1933
1934   if ((eh < 256) && (value < 2))
1935     {
1936       am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, eh, value);
1937       return 1;
1938     }
1939   else
1940     return 0;
1941 }
1942
1943
1944 static clib_error_t *
1945 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1946 {
1947   acl_main_t *am = &acl_main;
1948   if (0 == am->acl_mheap) {
1949     /* ACL heap is not initialized, so definitely nothing to do. */
1950     return 0;
1951   }
1952   if (0 == is_add) {
1953     vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
1954                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, sw_if_index);
1955     /* also unapply any ACLs in case the users did not do so. */
1956     macip_acl_interface_del_acl(am, sw_if_index);
1957     acl_interface_reset_inout_acls (sw_if_index, 0);
1958     acl_interface_reset_inout_acls (sw_if_index, 1);
1959   }
1960   return 0;
1961 }
1962
1963 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
1964
1965
1966
1967 static clib_error_t *
1968 acl_set_aclplugin_fn (vlib_main_t * vm,
1969                               unformat_input_t * input,
1970                               vlib_cli_command_t * cmd)
1971 {
1972   clib_error_t *error = 0;
1973   u32 timeout = 0;
1974   u32 val = 0;
1975   u32 eh_val = 0;
1976   uword memory_size = 0;
1977   acl_main_t *am = &acl_main;
1978
1979   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val)) {
1980     if(!acl_set_skip_ipv6_eh(eh_val, val)) {
1981       error = clib_error_return(0, "expecting eh=0..255, value=0..1");
1982     }
1983     goto done;
1984   }
1985   if (unformat (input, "use-hash-acl-matching %u", &val))
1986     {
1987       am->use_hash_acl_matching = (val !=0);
1988       goto done;
1989     }
1990   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
1991     {
1992       am->l4_match_nonfirst_fragment = (val != 0);
1993       goto done;
1994     }
1995   if (unformat (input, "heap"))
1996     {
1997       if (unformat(input, "main"))
1998         {
1999           if (unformat(input, "validate %u", &val))
2000             acl_plugin_acl_set_validate_heap(am, val);
2001           else if (unformat(input, "trace %u", &val))
2002             acl_plugin_acl_set_trace_heap(am, val);
2003           goto done;
2004         }
2005       else if (unformat(input, "hash"))
2006         {
2007           if (unformat(input, "validate %u", &val))
2008             acl_plugin_hash_acl_set_validate_heap(am, val);
2009           else if (unformat(input, "trace %u", &val))
2010             acl_plugin_hash_acl_set_trace_heap(am, val);
2011           goto done;
2012         }
2013       goto done;
2014     }
2015   if (unformat (input, "session")) {
2016     if (unformat (input, "table")) {
2017       /* The commands here are for tuning/testing. No user-serviceable parts inside */
2018       if (unformat (input, "max-entries")) {
2019         if (!unformat(input, "%u", &val)) {
2020           error = clib_error_return(0,
2021                                     "expecting maximum number of entries, got `%U`",
2022                                     format_unformat_error, input);
2023           goto done;
2024         } else {
2025           acl_set_session_max_entries(val);
2026           goto done;
2027         }
2028       }
2029       if (unformat (input, "hash-table-buckets")) {
2030         if (!unformat(input, "%u", &val)) {
2031           error = clib_error_return(0,
2032                                     "expecting maximum number of hash table buckets, got `%U`",
2033                                     format_unformat_error, input);
2034           goto done;
2035         } else {
2036           am->fa_conn_table_hash_num_buckets = val;
2037           goto done;
2038         }
2039       }
2040       if (unformat (input, "hash-table-memory")) {
2041         if (!unformat(input, "%U", unformat_memory_size, &memory_size)) {
2042           error = clib_error_return(0,
2043                                     "expecting maximum amount of hash table memory, got `%U`",
2044                                     format_unformat_error, input);
2045           goto done;
2046         } else {
2047           am->fa_conn_table_hash_memory_size = memory_size;
2048           goto done;
2049         }
2050       }
2051       goto done;
2052     }
2053     if (unformat (input, "timeout")) {
2054       if (unformat(input, "udp")) {
2055         if(unformat(input, "idle")) {
2056           if (!unformat(input, "%u", &timeout)) {
2057             error = clib_error_return(0,
2058                                       "expecting timeout value in seconds, got `%U`",
2059                                       format_unformat_error, input);
2060             goto done;
2061           } else {
2062             acl_set_timeout_sec(ACL_TIMEOUT_UDP_IDLE, timeout);
2063             goto done;
2064           }
2065         }
2066       }
2067       if (unformat(input, "tcp")) {
2068         if(unformat(input, "idle")) {
2069           if (!unformat(input, "%u", &timeout)) {
2070             error = clib_error_return(0,
2071                                       "expecting timeout value in seconds, got `%U`",
2072                                       format_unformat_error, input);
2073             goto done;
2074           } else {
2075             acl_set_timeout_sec(ACL_TIMEOUT_TCP_IDLE, timeout);
2076             goto done;
2077           }
2078         }
2079         if(unformat(input, "transient")) {
2080           if (!unformat(input, "%u", &timeout)) {
2081             error = clib_error_return(0,
2082                                       "expecting timeout value in seconds, got `%U`",
2083                                       format_unformat_error, input);
2084             goto done;
2085           } else {
2086             acl_set_timeout_sec(ACL_TIMEOUT_TCP_TRANSIENT, timeout);
2087             goto done;
2088           }
2089         }
2090       }
2091       goto done;
2092     }
2093   }
2094 done:
2095   return error;
2096 }
2097
2098 static u8 *
2099 my_format_mac_address (u8 * s, va_list * args)
2100 {
2101   u8 *a = va_arg (*args, u8 *);
2102   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
2103                  a[0], a[1], a[2], a[3], a[4], a[5]);
2104 }
2105
2106 static inline u8 *
2107 my_macip_acl_rule_t_pretty_format (u8 *out, va_list *args)
2108 {
2109   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
2110
2111   out = format(out, "%s action %d ip %U/%d mac %U mask %U",
2112                      a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
2113                      format_ip46_address, &a->src_ip_addr, IP46_TYPE_ANY,
2114                      a->src_prefixlen,
2115                      my_format_mac_address, a->src_mac,
2116                      my_format_mac_address, a->src_mac_mask);
2117   return(out);
2118 }
2119
2120 static void
2121 macip_acl_print(acl_main_t *am, u32 macip_acl_index)
2122 {
2123   vlib_main_t * vm = am->vlib_main;
2124   int i;
2125
2126   /* Don't try to print someone else's memory */
2127   if (macip_acl_index > vec_len(am->macip_acls))
2128     return;
2129
2130   macip_acl_list_t *a = vec_elt_at_index(am->macip_acls, macip_acl_index);
2131   int free_pool_slot = pool_is_free_index(am->macip_acls, macip_acl_index);
2132
2133   vlib_cli_output(vm, "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
2134                   macip_acl_index, a->count, vec_len(a->rules), a->tag, free_pool_slot);
2135   vlib_cli_output(vm, "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
2136                   a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
2137   for(i=0; i<vec_len(a->rules); i++)
2138     vlib_cli_output(vm, "    rule %d: %U\n", i, my_macip_acl_rule_t_pretty_format,
2139                     vec_elt_at_index(a->rules, i));
2140
2141 }
2142
2143 static clib_error_t *
2144 acl_show_aclplugin_macip_fn (vlib_main_t * vm,
2145                               unformat_input_t * input,
2146                               vlib_cli_command_t * cmd)
2147 {
2148   clib_error_t *error = 0;
2149   acl_main_t *am = &acl_main;
2150   int i;
2151   if (unformat (input, "interface"))
2152     {
2153       for(i=0; i < vec_len(am->macip_acl_by_sw_if_index); i++)
2154         {
2155           vlib_cli_output(vm, "  sw_if_index %d: %d\n", i, vec_elt(am->macip_acl_by_sw_if_index, i));
2156         }
2157     }
2158   else if (unformat (input, "acl"))
2159     {
2160       for(i=0; i < vec_len(am->macip_acls); i++)
2161         macip_acl_print(am, i);
2162     }
2163   return error;
2164 }
2165
2166
2167 static clib_error_t *
2168 acl_show_aclplugin_fn (vlib_main_t * vm,
2169                               unformat_input_t * input,
2170                               vlib_cli_command_t * cmd)
2171 {
2172   clib_error_t *error = 0;
2173   acl_main_t *am = &acl_main;
2174   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2175   u32 *pj;
2176
2177   vnet_sw_interface_t *swif;
2178
2179   if (unformat (input, "sessions"))
2180     {
2181       u8 * out0 = format(0, "");
2182       u16 wk;
2183       u32 show_bihash_verbose = 0;
2184       u32 show_session_thread_id = ~0;
2185       u32 show_session_session_index = ~0;
2186       unformat (input, "thread %u index %u", &show_session_thread_id, &show_session_session_index);
2187       unformat (input, "verbose %u", &show_bihash_verbose);
2188       {
2189         u64 n_adds = am->fa_session_total_adds;
2190         u64 n_dels = am->fa_session_total_dels;
2191         out0 = format(out0, "Sessions total: add %lu - del %lu = %lu\n", n_adds, n_dels, n_adds - n_dels);
2192       }
2193       out0 = format(out0, "\n\nPer-thread data:\n");
2194       for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2195         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2196         out0 = format(out0, "Thread #%d:\n", wk);
2197         if (show_session_thread_id == wk && show_session_session_index < pool_len(pw->fa_sessions_pool)) {
2198           out0 = format(out0, "  session index %u:\n", show_session_session_index);
2199           fa_session_t *sess = pw->fa_sessions_pool + show_session_session_index;
2200           u64 *m =  (u64 *)&sess->info;
2201           out0 = format(out0, "    info: %016llx %016llx %016llx %016llx %016llx %016llx\n", m[0], m[1], m[2], m[3], m[4], m[5]);
2202           out0 = format(out0, "    sw_if_index: %u\n", sess->sw_if_index);
2203           out0 = format(out0, "    tcp_flags_seen: %x\n", sess->tcp_flags_seen.as_u16);
2204           out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2205           out0 = format(out0, "    thread index: %u\n", sess->thread_index);
2206           out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2207           out0 = format(out0, "    link next index: %u\n", sess->link_next_idx);
2208           out0 = format(out0, "    link prev index: %u\n", sess->link_prev_idx);
2209           out0 = format(out0, "    link list id: %u\n", sess->link_list_id);
2210         }
2211         out0 = format(out0, "  connection add/del stats:\n", wk);
2212         pool_foreach (swif, im->sw_interfaces,
2213         ({
2214           u32 sw_if_index =  swif->sw_if_index;
2215           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;
2216           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;
2217           out0 = format(out0, "    sw_if_index %d: add %lu - del %lu = %lu\n", sw_if_index, n_adds, n_dels, n_adds - n_dels);
2218         }));
2219
2220         out0 = format(out0, "  connection timeout type lists:\n", wk);
2221         u8 tt = 0;
2222         for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2223           u32 head_session_index = pw->fa_conn_list_head[tt];
2224           out0 = format(out0, "  fa_conn_list_head[%d]: %d\n", tt, head_session_index);
2225           if (~0 != head_session_index) {
2226             fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
2227             out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2228             out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2229           }
2230         }
2231
2232         out0 = format(out0, "  Next expiry time: %lu\n", pw->next_expiry_time);
2233         out0 = format(out0, "  Requeue until time: %lu\n", pw->requeue_until_time);
2234         out0 = format(out0, "  Current time wait interval: %lu\n", pw->current_time_wait_interval);
2235         out0 = format(out0, "  Count of deleted sessions: %lu\n", pw->cnt_deleted_sessions);
2236         out0 = format(out0, "  Delete already deleted: %lu\n", pw->cnt_already_deleted_sessions);
2237         out0 = format(out0, "  Session timers restarted: %lu\n", pw->cnt_session_timer_restarted);
2238         out0 = format(out0, "  Swipe until this time: %lu\n", pw->swipe_end_time);
2239         out0 = format(out0, "  sw_if_index serviced bitmap: %U\n", format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
2240         out0 = format(out0, "  pending clear intfc bitmap : %U\n", format_bitmap_hex, pw->pending_clear_sw_if_index_bitmap);
2241         out0 = format(out0, "  clear in progress: %u\n", pw->clear_in_process);
2242         out0 = format(out0, "  interrupt is pending: %d\n", pw->interrupt_is_pending);
2243         out0 = format(out0, "  interrupt is needed: %d\n", pw->interrupt_is_needed);
2244         out0 = format(out0, "  interrupt is unwanted: %d\n", pw->interrupt_is_unwanted);
2245       }
2246       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
2247 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
2248       foreach_fa_cleaner_counter;
2249 #undef _
2250       vec_terminate_c_string(out0);
2251       vlib_cli_output(vm, "\n\n%s\n\n", out0);
2252       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
2253               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
2254               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);
2255
2256       vec_free(out0);
2257       show_fa_sessions_hash(vm, show_bihash_verbose);
2258     }
2259   else if (unformat (input, "interface"))
2260     {
2261       u32 sw_if_index = ~0;
2262       u32 swi;
2263       u8 * out0 = format(0, "");
2264       unformat (input, "sw_if_index %u", &sw_if_index);
2265       for(swi = 0; (swi < vec_len(am->input_acl_vec_by_sw_if_index)) ||
2266                    (swi < vec_len(am->output_acl_vec_by_sw_if_index)); swi++) {
2267         out0 = format(out0, "sw_if_index %d:\n", swi);
2268
2269         if ((swi < vec_len(am->input_acl_vec_by_sw_if_index)) &&
2270             (vec_len(am->input_acl_vec_by_sw_if_index[swi]) > 0)) {
2271           out0 = format(out0, "  input acl(s): ");
2272           vec_foreach(pj, am->input_acl_vec_by_sw_if_index[swi]) {
2273             out0 = format(out0, "%d ", *pj);
2274           }
2275           out0 = format(out0, "\n");
2276         }
2277
2278         if ((swi < vec_len(am->output_acl_vec_by_sw_if_index)) &&
2279             (vec_len(am->output_acl_vec_by_sw_if_index[swi]) > 0)) {
2280           out0 = format(out0, "  output acl(s): ");
2281           vec_foreach(pj, am->output_acl_vec_by_sw_if_index[swi]) {
2282             out0 = format(out0, "%d ", *pj);
2283           }
2284           out0 = format(out0, "\n");
2285         }
2286
2287       }
2288       vec_terminate_c_string(out0);
2289       vlib_cli_output(vm, "\n%s\n", out0);
2290       vec_free(out0);
2291     }
2292   else if (unformat (input, "acl"))
2293     {
2294       u32 acl_index = ~0;
2295       u32 i;
2296       u8 * out0 = format(0, "");
2297       unformat (input, "index %u", &acl_index);
2298       for(i=0; i<vec_len(am->acls); i++) {
2299         if (acl_is_not_defined(am, i)) {
2300           /* don't attempt to show the ACLs that do not exist */
2301           continue;
2302         }
2303         if ((acl_index != ~0) && (acl_index != i)) {
2304           continue;
2305         }
2306         out0 = format(out0, "acl-index %u count %u tag {%s}\n", i, am->acls[i].count, am->acls[i].tag);
2307         acl_rule_t *r;
2308         int j;
2309         for(j=0; j<am->acls[i].count; j++) {
2310           r = &am->acls[i].rules[j];
2311           out0 = format(out0, "  %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
2312           out0 = format_acl_action(out0, r->is_permit);
2313           out0 = format(out0, " src %U/%d", format_ip46_address, &r->src, IP46_TYPE_ANY, r->src_prefixlen);
2314           out0 = format(out0, " dst %U/%d", format_ip46_address, &r->dst, IP46_TYPE_ANY, r->dst_prefixlen);
2315           out0 = format(out0, " proto %d", r->proto);
2316           out0 = format(out0, " sport %d", r->src_port_or_type_first);
2317           if (r->src_port_or_type_first != r->src_port_or_type_last) {
2318             out0 = format(out0, "-%d", r->src_port_or_type_last);
2319           }
2320           out0 = format(out0, " dport %d", r->dst_port_or_code_first);
2321           if (r->dst_port_or_code_first != r->dst_port_or_code_last) {
2322             out0 = format(out0, "-%d", r->dst_port_or_code_last);
2323           }
2324           if (r->tcp_flags_mask || r->tcp_flags_value) {
2325             out0 = format(out0, " tcpflags %d mask %d", r->tcp_flags_value, r->tcp_flags_mask);
2326           }
2327           out0 = format(out0, "\n");
2328         }
2329
2330         if (i<vec_len(am->input_sw_if_index_vec_by_acl)) {
2331           out0 = format(out0, "  applied inbound on sw_if_index: ");
2332           vec_foreach(pj, am->input_sw_if_index_vec_by_acl[i]) {
2333             out0 = format(out0, "%d ", *pj);
2334           }
2335           out0 = format(out0, "\n");
2336         }
2337         if (i<vec_len(am->output_sw_if_index_vec_by_acl)) {
2338           out0 = format(out0, "  applied outbound on sw_if_index: ");
2339           vec_foreach(pj, am->output_sw_if_index_vec_by_acl[i]) {
2340             out0 = format(out0, "%d ", *pj);
2341           }
2342           out0 = format(out0, "\n");
2343         }
2344       }
2345       vec_terminate_c_string(out0);
2346       vlib_cli_output(vm, "\n%s\n", out0);
2347       vec_free(out0);
2348     }
2349   else if (unformat (input, "memory"))
2350     {
2351       vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
2352       if (am->acl_mheap) {
2353         vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
2354       } else {
2355         vlib_cli_output (vm, " Not initialized\n");
2356       }
2357       vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
2358       if (am->hash_lookup_mheap) {
2359         vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
2360       } else {
2361         vlib_cli_output (vm, " Not initialized\n");
2362       }
2363     }
2364   else if (unformat (input, "tables"))
2365     {
2366       ace_mask_type_entry_t *mte;
2367       u32 acl_index = ~0;
2368       u32 sw_if_index = ~0;
2369       int show_acl_hash_info = 0;
2370       int show_applied_info = 0;
2371       int show_mask_type = 0;
2372       int show_bihash = 0;
2373       u32 show_bihash_verbose = 0;
2374
2375       if (unformat (input, "acl")) {
2376         show_acl_hash_info = 1;
2377         /* mask-type is handy to see as well right there */
2378         show_mask_type = 1;
2379         unformat (input, "index %u", &acl_index);
2380       } else if (unformat (input, "applied")) {
2381         show_applied_info = 1;
2382         unformat (input, "sw_if_index %u", &sw_if_index);
2383       } else if (unformat (input, "mask")) {
2384         show_mask_type = 1;
2385       } else if (unformat (input, "hash")) {
2386         show_bihash = 1;
2387         unformat (input, "verbose %u", &show_bihash_verbose);
2388       }
2389
2390       if ( ! (show_mask_type || show_acl_hash_info || show_applied_info || show_bihash) ) {
2391         /* if no qualifiers specified, show all */
2392         show_mask_type = 1;
2393         show_acl_hash_info = 1;
2394         show_applied_info = 1;
2395         show_bihash = 1;
2396       }
2397
2398       if (show_mask_type) {
2399         vlib_cli_output(vm, "Mask-type entries:");
2400         /* *INDENT-OFF* */
2401         pool_foreach(mte, am->ace_mask_type_pool,
2402         ({
2403           vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
2404                         mte - am->ace_mask_type_pool,
2405                         mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
2406                         mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
2407         }));
2408         /* *INDENT-ON* */
2409       }
2410
2411       if (show_acl_hash_info) {
2412         u32 i,j;
2413         u8 * out0 = format(0, "");
2414         u64 *m;
2415         out0 = format(out0, "Mask-ready ACL representations\n");
2416         for (i=0; i< vec_len(am->hash_acl_infos); i++) {
2417           if ((acl_index != ~0) && (acl_index != i)) {
2418             continue;
2419           }
2420           hash_acl_info_t *ha = &am->hash_acl_infos[i];
2421           out0 = format(out0, "acl-index %u bitmask-ready layout\n", i);
2422           out0 = format(out0, "  mask type index bitmap: %U\n", format_bitmap_hex, ha->mask_type_index_bitmap);
2423           for(j=0; j<vec_len(ha->rules); j++) {
2424             hash_ace_info_t *pa = &ha->rules[j];
2425             m = (u64 *)&pa->match;
2426             out0 = format(out0, "    %4d: %016llx %016llx %016llx %016llx %016llx %016llx mask index %d acl %d rule %d action %d src/dst portrange not ^2: %d,%d\n",
2427                                 j, m[0], m[1], m[2], m[3], m[4], m[5], pa->mask_type_index,
2428                                 pa->acl_index, pa->ace_index, pa->action,
2429                                 pa->src_portrange_not_powerof2, pa->dst_portrange_not_powerof2);
2430           }
2431         }
2432         vec_terminate_c_string(out0);
2433         vlib_cli_output(vm, "\n%s\n", out0);
2434         vec_free(out0);
2435       }
2436
2437       if (show_applied_info) {
2438         u32 swi, j;
2439         u8 * out0 = format(0, "");
2440         out0 = format(out0, "Applied lookup entries for interfaces\n");
2441
2442         for(swi = 0; (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) ||
2443                    (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) ||
2444                    (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) ||
2445                    (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)); swi++) {
2446           if ((sw_if_index != ~0) && (sw_if_index != swi)) {
2447             continue;
2448           }
2449           out0 = format(out0, "sw_if_index %d:\n", swi);
2450           if (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) {
2451             applied_hash_acl_info_t *pal = &am->input_applied_hash_acl_info_by_sw_if_index[swi];
2452             out0 = format(out0, "  input lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2453             out0 = format(out0, "  input applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2454           }
2455           if (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) {
2456             out0 = format(out0, "  input lookup applied entries:\n");
2457             for(j=0; j<vec_len(am->input_hash_entry_vec_by_sw_if_index[swi]); j++) {
2458               applied_hash_ace_entry_t *pae = &am->input_hash_entry_vec_by_sw_if_index[swi][j];
2459               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d\n",
2460                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2461                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index);
2462             }
2463           }
2464
2465           if (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) {
2466             applied_hash_acl_info_t *pal = &am->output_applied_hash_acl_info_by_sw_if_index[swi];
2467             out0 = format(out0, "  output lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2468             out0 = format(out0, "  output applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2469           }
2470           if (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)) {
2471             out0 = format(out0, "  output lookup applied entries:\n");
2472             for(j=0; j<vec_len(am->output_hash_entry_vec_by_sw_if_index[swi]); j++) {
2473               applied_hash_ace_entry_t *pae = &am->output_hash_entry_vec_by_sw_if_index[swi][j];
2474               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d\n",
2475                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2476                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index);
2477             }
2478           }
2479
2480         }
2481         vec_terminate_c_string(out0);
2482         vlib_cli_output(vm, "\n%s\n", out0);
2483         vec_free(out0);
2484       }
2485
2486       if (show_bihash) {
2487         show_hash_acl_hash(vm, am, show_bihash_verbose);
2488       }
2489     }
2490   return error;
2491 }
2492
2493 static clib_error_t *
2494 acl_clear_aclplugin_fn (vlib_main_t * vm,
2495                               unformat_input_t * input,
2496                               vlib_cli_command_t * cmd)
2497 {
2498   clib_error_t *error = 0;
2499   acl_main_t *am = &acl_main;
2500   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2501                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
2502   return error;
2503 }
2504
2505  /* *INDENT-OFF* */
2506 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
2507     .path = "set acl-plugin",
2508     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
2509     .function = acl_set_aclplugin_fn,
2510 };
2511
2512 VLIB_CLI_COMMAND (aclplugin_show_command, static) = {
2513     .path = "show acl-plugin",
2514     .short_help = "show acl-plugin {sessions|acl|interface|tables}",
2515     .function = acl_show_aclplugin_fn,
2516 };
2517
2518 VLIB_CLI_COMMAND (aclplugin_show_macip_command, static) = {
2519     .path = "show acl-plugin macip",
2520     .short_help = "show acl-plugin macip {acl|interface}",
2521     .function = acl_show_aclplugin_macip_fn,
2522 };
2523
2524
2525 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
2526     .path = "clear acl-plugin sessions",
2527     .short_help = "clear acl-plugin sessions",
2528     .function = acl_clear_aclplugin_fn,
2529 };
2530 /* *INDENT-ON* */
2531
2532
2533
2534 static clib_error_t *
2535 acl_init (vlib_main_t * vm)
2536 {
2537   acl_main_t *am = &acl_main;
2538   clib_error_t *error = 0;
2539   memset (am, 0, sizeof (*am));
2540   am->vlib_main = vm;
2541   am->vnet_main = vnet_get_main ();
2542
2543   u8 *name = format (0, "acl_%08x%c", api_version, 0);
2544
2545   /* Ask for a correctly-sized block of API message decode slots */
2546   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
2547                                             VL_MSG_FIRST_AVAILABLE);
2548
2549   error = acl_plugin_api_hookup (vm);
2550
2551  /* Add our API messages to the global name_crc hash table */
2552   setup_message_id_table (am, &api_main);
2553
2554   vec_free (name);
2555
2556   acl_setup_fa_nodes();
2557
2558   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
2559   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
2560   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;
2561
2562   am->fa_conn_table_hash_num_buckets = ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
2563   am->fa_conn_table_hash_memory_size = ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
2564   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
2565   vlib_thread_main_t *tm = vlib_get_thread_main ();
2566   vec_validate(am->per_worker_data, tm->n_vlib_mains-1);
2567   {
2568     u16 wk;
2569     u8 tt;
2570     for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2571       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2572       vec_validate(pw->fa_conn_list_head, ACL_N_TIMEOUTS-1);
2573       vec_validate(pw->fa_conn_list_tail, ACL_N_TIMEOUTS-1);
2574       for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2575         pw->fa_conn_list_head[tt] = ~0;
2576         pw->fa_conn_list_tail[tt] = ~0;
2577       }
2578     }
2579   }
2580
2581   am->fa_min_deleted_sessions_per_interval = ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
2582   am->fa_max_deleted_sessions_per_interval = ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
2583   am->fa_cleaner_wait_time_increment = ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
2584
2585   am->fa_cleaner_cnt_delete_by_sw_index = 0;
2586   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
2587   am->fa_cleaner_cnt_unknown_event = 0;
2588   am->fa_cleaner_cnt_timer_restarted = 0;
2589   am->fa_cleaner_cnt_wait_with_timeout = 0;
2590
2591
2592 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
2593   foreach_acl_eh
2594 #undef _
2595
2596   am->l4_match_nonfirst_fragment = 1;
2597
2598   /* use the new fancy hash-based matching */
2599   am->use_hash_acl_matching = 1;
2600
2601   return error;
2602 }
2603
2604 VLIB_INIT_FUNCTION (acl_init);