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