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