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