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