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