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