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