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