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