plugins: clean up plugin descriptions
[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           if (~0 == am->interface_acl_user_id)
793             am->interface_acl_user_id =
794               acl_plugin.register_user_module ("interface ACL", "sw_if_index",
795                                                "is_input");
796           lc_index =
797             acl_plugin.get_lookup_context_index (am->interface_acl_user_id,
798                                                  sw_if_index, is_input);
799           (*pinout_lc_index_by_sw_if_index)[sw_if_index] = lc_index;
800         }
801       acl_plugin.set_acl_vec_for_context (lc_index, vec_acl_list_index);
802     }
803   else
804     {
805       if (~0 != (*pinout_lc_index_by_sw_if_index)[sw_if_index])
806         {
807           acl_plugin.put_lookup_context_index ((*pinout_lc_index_by_sw_if_index)[sw_if_index]);
808           (*pinout_lc_index_by_sw_if_index)[sw_if_index] = ~0;
809         }
810     }
811
812   /* ensure ACL processing is enabled/disabled as needed */
813   acl_interface_inout_enable_disable (am, sw_if_index, is_input,
814                                       vec_len (vec_acl_list_index) > 0);
815
816 done:
817   clib_bitmap_free (change_acl_bitmap);
818   clib_bitmap_free (seen_acl_bitmap);
819   clib_bitmap_free (old_seen_acl_bitmap);
820   return rv;
821 }
822
823 static void
824 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input,
825                                 int *may_clear_sessions)
826 {
827   acl_main_t *am = &acl_main;
828   void *oldheap = acl_set_heap (am);
829   acl_interface_set_inout_acl_list (am, sw_if_index, is_input, 0,
830                                     may_clear_sessions);
831   clib_mem_set_heap (oldheap);
832 }
833
834 static int
835 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
836                                  u32 acl_list_index)
837 {
838
839   acl_main_t *am = &acl_main;
840   u32 *acl_vec = 0;
841   int may_clear_sessions = 1;
842
843   int error_already_applied = is_input ? VNET_API_ERROR_ACL_IN_USE_INBOUND
844     : VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
845
846   u32 ***pinout_acl_vec_by_sw_if_index =
847     is_input ? &am->
848     input_acl_vec_by_sw_if_index : &am->output_acl_vec_by_sw_if_index;
849   int rv = 0;
850   void *oldheap = acl_set_heap (am);
851
852   if (is_add)
853     {
854       vec_validate ((*pinout_acl_vec_by_sw_if_index), sw_if_index);
855       u32 index = vec_search ((*pinout_acl_vec_by_sw_if_index)[sw_if_index],
856                               acl_list_index);
857
858       if (~0 != index)
859         {
860           rv = error_already_applied;
861           goto done;
862         }
863
864       acl_vec = vec_dup ((*pinout_acl_vec_by_sw_if_index)[sw_if_index]);
865       vec_add1 (acl_vec, acl_list_index);
866     }
867   else
868     {
869       if (sw_if_index >= vec_len (*pinout_acl_vec_by_sw_if_index))
870         {
871           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
872           goto done;
873         }
874
875       u32 index = vec_search ((*pinout_acl_vec_by_sw_if_index)[sw_if_index],
876                               acl_list_index);
877
878       if (~0 == index)
879         {
880           rv = VNET_API_ERROR_NO_SUCH_ENTRY;
881           goto done;
882         }
883
884       acl_vec = vec_dup ((*pinout_acl_vec_by_sw_if_index)[sw_if_index]);
885       vec_del1 (acl_vec, index);
886     }
887
888   rv = acl_interface_set_inout_acl_list (am, sw_if_index, is_input, acl_vec,
889                                          &may_clear_sessions);
890 done:
891   vec_free (acl_vec);
892   clib_mem_set_heap (oldheap);
893   return rv;
894 }
895
896 static int
897 acl_set_etype_whitelists (acl_main_t * am, u32 sw_if_index, u16 * vec_in,
898                           u16 * vec_out)
899 {
900   vec_validate (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
901   vec_validate (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
902
903   vec_free (am->input_etype_whitelist_by_sw_if_index[sw_if_index]);
904   vec_free (am->output_etype_whitelist_by_sw_if_index[sw_if_index]);
905
906   am->input_etype_whitelist_by_sw_if_index[sw_if_index] = vec_in;
907   am->output_etype_whitelist_by_sw_if_index[sw_if_index] = vec_out;
908
909   /*
910    * if there are already inbound/outbound ACLs applied, toggle the
911    * enable/disable - this will recreate the necessary tables.
912    */
913
914   if (vec_len (am->input_acl_vec_by_sw_if_index) > sw_if_index)
915     {
916       if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
917         {
918           acl_interface_in_enable_disable (am, sw_if_index, 0);
919           acl_interface_in_enable_disable (am, sw_if_index, 1);
920         }
921     }
922   if (vec_len (am->output_acl_vec_by_sw_if_index) > sw_if_index)
923     {
924       if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
925         {
926           acl_interface_out_enable_disable (am, sw_if_index, 0);
927           acl_interface_out_enable_disable (am, sw_if_index, 1);
928         }
929     }
930   return 0;
931 }
932
933
934 typedef struct
935 {
936   u8 is_ipv6;
937   u8 has_egress;
938   u8 mac_mask[6];
939   u8 prefix_len;
940   u32 count;
941   u32 table_index;
942   u32 arp_table_index;
943   u32 dot1q_table_index;
944   u32 dot1ad_table_index;
945   u32 arp_dot1q_table_index;
946   u32 arp_dot1ad_table_index;
947   /* egress tables */
948   u32 out_table_index;
949   u32 out_arp_table_index;
950   u32 out_dot1q_table_index;
951   u32 out_dot1ad_table_index;
952   u32 out_arp_dot1q_table_index;
953   u32 out_arp_dot1ad_table_index;
954 } macip_match_type_t;
955
956 static u32
957 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
958                        u8 is_ipv6)
959 {
960   u32 i;
961   if (mv)
962     {
963       for (i = 0; i < vec_len (mv); i++)
964         {
965           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
966               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
967             {
968               return i;
969             }
970         }
971     }
972   return ~0;
973 }
974
975
976 /* Get metric used to sort match types.
977    The more specific and the more often seen - the bigger the metric */
978 static int
979 match_type_metric (macip_match_type_t * m)
980 {
981   unsigned int mac_bits_set = 0;
982   unsigned int mac_byte;
983   int i;
984   for (i = 0; i < 6; i++)
985     {
986       mac_byte = m->mac_mask[i];
987       for (; mac_byte; mac_byte >>= 1)
988         mac_bits_set += mac_byte & 1;
989     }
990   /*
991    * Attempt to place the more specific and the more used rules on top.
992    * There are obvious caveat corner cases to this, but they do not
993    * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
994    * going with a wildcard IPv4 with a specific MAC).
995    */
996   return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
997 }
998
999 static int
1000 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
1001 {
1002   /* Ascending sort based on the metric values */
1003   return match_type_metric (m1) - match_type_metric (m2);
1004 }
1005
1006 /* Get the offset of L3 source within ethernet packet */
1007 static int
1008 get_l3_src_offset (int is6)
1009 {
1010   if (is6)
1011     return (sizeof (ethernet_header_t) +
1012             offsetof (ip6_header_t, src_address));
1013   else
1014     return (sizeof (ethernet_header_t) +
1015             offsetof (ip4_header_t, src_address));
1016 }
1017
1018 static int
1019 get_l3_dst_offset (int is6)
1020 {
1021   if (is6)
1022     return (sizeof (ethernet_header_t) +
1023             offsetof (ip6_header_t, dst_address));
1024   else
1025     return (sizeof (ethernet_header_t) +
1026             offsetof (ip4_header_t, dst_address));
1027 }
1028
1029 /*
1030  * return if the is_permit value also requires to create the egress tables
1031  * For backwards compatibility, we keep the is_permit = 1 to only
1032  * create the ingress tables, and the new value of 3 will also
1033  * create the egress tables based on destination.
1034  */
1035 static int
1036 macip_permit_also_egress (u8 is_permit)
1037 {
1038   return (is_permit == 3);
1039 }
1040
1041 static int
1042 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
1043 {
1044   macip_match_type_t *mvec = NULL;
1045   macip_match_type_t *mt;
1046   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1047   int i;
1048   u32 match_type_index;
1049   u32 last_table;
1050   u32 out_last_table;
1051   u8 mask[5 * 16];
1052   vnet_classify_main_t *cm = &vnet_classify_main;
1053
1054   /* Count the number of different types of rules */
1055   for (i = 0; i < a->count; i++)
1056     {
1057       if (~0 ==
1058           (match_type_index =
1059            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1060                                   a->rules[i].src_prefixlen,
1061                                   a->rules[i].is_ipv6)))
1062         {
1063           match_type_index = vec_len (mvec);
1064           vec_validate (mvec, match_type_index);
1065           memcpy (mvec[match_type_index].mac_mask,
1066                   a->rules[i].src_mac_mask, 6);
1067           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1068           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1069           mvec[match_type_index].has_egress = 0;
1070           mvec[match_type_index].table_index = ~0;
1071           mvec[match_type_index].arp_table_index = ~0;
1072           mvec[match_type_index].dot1q_table_index = ~0;
1073           mvec[match_type_index].dot1ad_table_index = ~0;
1074           mvec[match_type_index].arp_dot1q_table_index = ~0;
1075           mvec[match_type_index].arp_dot1ad_table_index = ~0;
1076           mvec[match_type_index].out_table_index = ~0;
1077           mvec[match_type_index].out_arp_table_index = ~0;
1078           mvec[match_type_index].out_dot1q_table_index = ~0;
1079           mvec[match_type_index].out_dot1ad_table_index = ~0;
1080           mvec[match_type_index].out_arp_dot1q_table_index = ~0;
1081           mvec[match_type_index].out_arp_dot1ad_table_index = ~0;
1082         }
1083       mvec[match_type_index].count++;
1084       mvec[match_type_index].has_egress |=
1085         macip_permit_also_egress (a->rules[i].is_permit);
1086     }
1087   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1088   vec_sort_with_function (mvec, match_type_compare);
1089   /* Create the classifier tables */
1090   last_table = ~0;
1091   out_last_table = ~0;
1092   /* First add ARP tables */
1093   vec_foreach (mt, mvec)
1094   {
1095     int mask_len;
1096     int is6 = mt->is_ipv6;
1097     int tags;
1098     u32 *last_tag_table;
1099     u32 *out_last_tag_table;
1100     u32 l3_offset;
1101
1102     if (!is6)
1103       {
1104         /*
1105            0                   1                   2                   3
1106            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
1107            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1108            |                      Destination Address                      |
1109            +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1110            |                               |                               |
1111            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
1112            |                         Source Address                        |
1113            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1114            |           EtherType           |         Hardware Type         |
1115            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1116            |         Protocol Type         |  Hw addr len  | Proto addr len|
1117            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1118            |             Opcode            |                               |
1119            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
1120            |                    Sender Hardware Address                    |
1121            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1122            |                    Sender Protocol Address                    |
1123            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1124            |                    Target Hardware Address                    |
1125            +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1126            |                               |     TargetProtocolAddress     |
1127            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1128            |                               |
1129            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1130          */
1131         for (tags = 2; tags >= 0; tags--)
1132           {
1133             clib_memset (mask, 0, sizeof (mask));
1134             /* source MAC address */
1135             memcpy (&mask[6], mt->mac_mask, 6);
1136
1137             switch (tags)
1138               {
1139               case 0:
1140               default:
1141                 clib_memset (&mask[12], 0xff, 2);       /* ethernet protocol */
1142                 l3_offset = 14;
1143                 last_tag_table = &mt->arp_table_index;
1144                 break;
1145               case 1:
1146                 clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
1147                 clib_memset (&mask[16], 0xff, 2);       /* ethernet protocol */
1148                 l3_offset = 18;
1149                 last_tag_table = &mt->arp_dot1q_table_index;
1150                 break;
1151               case 2:
1152                 clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
1153                 clib_memset (&mask[16], 0xff, 2);       /* VLAN tag2 */
1154                 clib_memset (&mask[20], 0xff, 2);       /* ethernet protocol */
1155                 l3_offset = 22;
1156                 last_tag_table = &mt->arp_dot1ad_table_index;
1157                 break;
1158               }
1159
1160             /* sender hardware address within ARP */
1161             memcpy (&mask[l3_offset + 8], mt->mac_mask, 6);
1162             /* sender protocol address within ARP */
1163             for (i = 0; i < (mt->prefix_len / 8); i++)
1164               mask[l3_offset + 14 + i] = 0xff;
1165             if (mt->prefix_len % 8)
1166               mask[l3_offset + 14 + (mt->prefix_len / 8)] =
1167                 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1168
1169             mask_len = ((l3_offset + 14 + ((mt->prefix_len + 7) / 8) +
1170                          (sizeof (u32x4) -
1171                           1)) / sizeof (u32x4)) * sizeof (u32x4);
1172             acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1173                                               (~0 == last_table) ? 0 : ~0,
1174                                               last_tag_table, 1);
1175             last_table = *last_tag_table;
1176             if (mt->has_egress)
1177               {
1178                 /* egress ARP table */
1179                 clib_memset (mask, 0, sizeof (mask));
1180
1181                 switch (tags)
1182                   {
1183                   case 0:
1184                   default:
1185                     clib_memset (&mask[12], 0xff, 2);   /* ethernet protocol */
1186                     l3_offset = 14;
1187                     out_last_tag_table = &mt->out_arp_table_index;
1188                     break;
1189                   case 1:
1190                     clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
1191                     clib_memset (&mask[16], 0xff, 2);   /* ethernet protocol */
1192                     l3_offset = 18;
1193                     out_last_tag_table = &mt->out_arp_dot1q_table_index;
1194                     break;
1195                   case 2:
1196                     clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
1197                     clib_memset (&mask[16], 0xff, 2);   /* VLAN tag2 */
1198                     clib_memset (&mask[20], 0xff, 2);   /* ethernet protocol */
1199                     l3_offset = 22;
1200                     out_last_tag_table = &mt->out_arp_dot1ad_table_index;
1201                     break;
1202                   }
1203
1204                 /* AYXX: FIXME here - can we tighten the ARP-related table more ? */
1205                 /* mask captures just the destination and the ethertype */
1206                 mask_len = ((l3_offset +
1207                              (sizeof (u32x4) -
1208                               1)) / sizeof (u32x4)) * sizeof (u32x4);
1209                 acl_classify_add_del_table_small (cm, mask, mask_len,
1210                                                   out_last_table,
1211                                                   (~0 ==
1212                                                    out_last_table) ? 0 : ~0,
1213                                                   out_last_tag_table, 1);
1214                 out_last_table = *out_last_tag_table;
1215               }
1216           }
1217       }
1218   }
1219   /* Now add IP[46] tables */
1220   vec_foreach (mt, mvec)
1221   {
1222     int mask_len;
1223     int is6 = mt->is_ipv6;
1224     int l3_src_offs;
1225     int l3_dst_offs;
1226     int tags;
1227     u32 *last_tag_table;
1228     u32 *out_last_tag_table;
1229
1230     /*
1231      * create chained tables for VLAN (no-tags, dot1q and dot1ad) packets
1232      */
1233     for (tags = 2; tags >= 0; tags--)
1234       {
1235         clib_memset (mask, 0, sizeof (mask));
1236         memcpy (&mask[6], mt->mac_mask, 6);
1237         l3_src_offs = tags * 4 + get_l3_src_offset (is6);
1238         switch (tags)
1239           {
1240           case 0:
1241           default:
1242             clib_memset (&mask[12], 0xff, 2);   /* ethernet protocol */
1243             last_tag_table = &mt->table_index;
1244             break;
1245           case 1:
1246             clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
1247             clib_memset (&mask[16], 0xff, 2);   /* ethernet protocol */
1248             last_tag_table = &mt->dot1q_table_index;
1249             break;
1250           case 2:
1251             clib_memset (&mask[12], 0xff, 2);   /* VLAN tag1 */
1252             clib_memset (&mask[16], 0xff, 2);   /* VLAN tag2 */
1253             clib_memset (&mask[20], 0xff, 2);   /* ethernet protocol */
1254             last_tag_table = &mt->dot1ad_table_index;
1255             break;
1256           }
1257         for (i = 0; i < (mt->prefix_len / 8); i++)
1258           {
1259             mask[l3_src_offs + i] = 0xff;
1260           }
1261         if (mt->prefix_len % 8)
1262           {
1263             mask[l3_src_offs + (mt->prefix_len / 8)] =
1264               0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1265           }
1266         /*
1267          * Round-up the number of bytes needed to store the prefix,
1268          * and round up the number of vectors too
1269          */
1270         mask_len = ((l3_src_offs + ((mt->prefix_len + 7) / 8) +
1271                      (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
1272         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1273                                           (~0 == last_table) ? 0 : ~0,
1274                                           last_tag_table, 1);
1275         last_table = *last_tag_table;
1276       }
1277     if (mt->has_egress)
1278       {
1279         for (tags = 2; tags >= 0; tags--)
1280           {
1281             clib_memset (mask, 0, sizeof (mask));
1282             /* MAC destination */
1283             memcpy (&mask[0], mt->mac_mask, 6);
1284             l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
1285             switch (tags)
1286               {
1287               case 0:
1288               default:
1289                 clib_memset (&mask[12], 0xff, 2);       /* ethernet protocol */
1290                 out_last_tag_table = &mt->out_table_index;
1291                 break;
1292               case 1:
1293                 clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
1294                 clib_memset (&mask[16], 0xff, 2);       /* ethernet protocol */
1295                 out_last_tag_table = &mt->out_dot1q_table_index;
1296                 break;
1297               case 2:
1298                 clib_memset (&mask[12], 0xff, 2);       /* VLAN tag1 */
1299                 clib_memset (&mask[16], 0xff, 2);       /* VLAN tag2 */
1300                 clib_memset (&mask[20], 0xff, 2);       /* ethernet protocol */
1301                 out_last_tag_table = &mt->out_dot1ad_table_index;
1302                 break;
1303               }
1304             for (i = 0; i < (mt->prefix_len / 8); i++)
1305               {
1306                 mask[l3_dst_offs + i] = 0xff;
1307               }
1308             if (mt->prefix_len % 8)
1309               {
1310                 mask[l3_dst_offs + (mt->prefix_len / 8)] =
1311                   0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1312               }
1313             /*
1314              * Round-up the number of bytes needed to store the prefix,
1315              * and round up the number of vectors too
1316              */
1317             mask_len = ((l3_dst_offs + ((mt->prefix_len + 7) / 8) +
1318                          (sizeof (u32x4) -
1319                           1)) / sizeof (u32x4)) * sizeof (u32x4);
1320             acl_classify_add_del_table_small (cm, mask, mask_len,
1321                                               out_last_table,
1322                                               (~0 == out_last_table) ? 0 : ~0,
1323                                               out_last_tag_table, 1);
1324             out_last_table = *out_last_tag_table;
1325           }
1326       }
1327   }
1328   a->ip4_table_index = last_table;
1329   a->ip6_table_index = last_table;
1330   a->l2_table_index = last_table;
1331
1332   a->out_ip4_table_index = out_last_table;
1333   a->out_ip6_table_index = out_last_table;
1334   a->out_l2_table_index = out_last_table;
1335
1336   /* Populate the classifier tables with rules from the MACIP ACL */
1337   for (i = 0; i < a->count; i++)
1338     {
1339       u32 action = 0;
1340       u32 metadata = 0;
1341       int is6 = a->rules[i].is_ipv6;
1342       int l3_src_offs;
1343       int l3_dst_offs;
1344       u32 tag_table;
1345       int tags, eth;
1346
1347       match_type_index =
1348         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1349                                a->rules[i].src_prefixlen,
1350                                a->rules[i].is_ipv6);
1351       ASSERT (match_type_index != ~0);
1352
1353       for (tags = 2; tags >= 0; tags--)
1354         {
1355           clib_memset (mask, 0, sizeof (mask));
1356           l3_src_offs = tags * 4 + get_l3_src_offset (is6);
1357           memcpy (&mask[6], a->rules[i].src_mac, 6);
1358           switch (tags)
1359             {
1360             case 0:
1361             default:
1362               tag_table = mvec[match_type_index].table_index;
1363               eth = 12;
1364               break;
1365             case 1:
1366               tag_table = mvec[match_type_index].dot1q_table_index;
1367               mask[12] = 0x81;
1368               mask[13] = 0x00;
1369               eth = 16;
1370               break;
1371             case 2:
1372               tag_table = mvec[match_type_index].dot1ad_table_index;
1373               mask[12] = 0x88;
1374               mask[13] = 0xa8;
1375               mask[16] = 0x81;
1376               mask[17] = 0x00;
1377               eth = 20;
1378               break;
1379             }
1380           if (is6)
1381             {
1382               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1383               mask[eth] = 0x86;
1384               mask[eth + 1] = 0xdd;
1385             }
1386           else
1387             {
1388               memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1389               mask[eth] = 0x08;
1390               mask[eth + 1] = 0x00;
1391             }
1392
1393           /* add session to table mvec[match_type_index].table_index; */
1394           vnet_classify_add_del_session (cm, tag_table,
1395                                          mask, a->rules[i].is_permit ? ~0 : 0,
1396                                          i, 0, action, metadata, 1);
1397           clib_memset (&mask[12], 0, sizeof (mask) - 12);
1398         }
1399
1400       /* add ARP table entry too */
1401       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1402         {
1403           clib_memset (mask, 0, sizeof (mask));
1404           memcpy (&mask[6], a->rules[i].src_mac, 6);
1405
1406           for (tags = 2; tags >= 0; tags--)
1407             {
1408               switch (tags)
1409                 {
1410                 case 0:
1411                 default:
1412                   tag_table = mvec[match_type_index].arp_table_index;
1413                   mask[12] = 0x08;
1414                   mask[13] = 0x06;
1415                   l3_src_offs = 14;
1416                   break;
1417                 case 1:
1418                   tag_table = mvec[match_type_index].arp_dot1q_table_index;
1419                   mask[12] = 0x81;
1420                   mask[13] = 0x00;
1421                   mask[16] = 0x08;
1422                   mask[17] = 0x06;
1423                   l3_src_offs = 18;
1424                   break;
1425                 case 2:
1426                   tag_table = mvec[match_type_index].arp_dot1ad_table_index;
1427                   mask[12] = 0x88;
1428                   mask[13] = 0xa8;
1429                   mask[16] = 0x81;
1430                   mask[17] = 0x00;
1431                   mask[20] = 0x08;
1432                   mask[21] = 0x06;
1433                   l3_src_offs = 22;
1434                   break;
1435                 }
1436
1437               memcpy (&mask[l3_src_offs + 8], a->rules[i].src_mac, 6);
1438               memcpy (&mask[l3_src_offs + 14], &a->rules[i].src_ip_addr.ip4,
1439                       4);
1440               vnet_classify_add_del_session (cm, tag_table, mask,
1441                                              a->rules[i].is_permit ? ~0 : 0,
1442                                              i, 0, action, metadata, 1);
1443             }
1444         }
1445       if (macip_permit_also_egress (a->rules[i].is_permit))
1446         {
1447           /* Add the egress entry with destination set */
1448           for (tags = 2; tags >= 0; tags--)
1449             {
1450               clib_memset (mask, 0, sizeof (mask));
1451               l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
1452               /* src mac in the other direction becomes dst */
1453               memcpy (&mask[0], a->rules[i].src_mac, 6);
1454               switch (tags)
1455                 {
1456                 case 0:
1457                 default:
1458                   tag_table = mvec[match_type_index].out_table_index;
1459                   eth = 12;
1460                   break;
1461                 case 1:
1462                   tag_table = mvec[match_type_index].out_dot1q_table_index;
1463                   mask[12] = 0x81;
1464                   mask[13] = 0x00;
1465                   eth = 16;
1466                   break;
1467                 case 2:
1468                   tag_table = mvec[match_type_index].out_dot1ad_table_index;
1469                   mask[12] = 0x88;
1470                   mask[13] = 0xa8;
1471                   mask[16] = 0x81;
1472                   mask[17] = 0x00;
1473                   eth = 20;
1474                   break;
1475                 }
1476               if (is6)
1477                 {
1478                   memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip6,
1479                           16);
1480                   mask[eth] = 0x86;
1481                   mask[eth + 1] = 0xdd;
1482                 }
1483               else
1484                 {
1485                   memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip4,
1486                           4);
1487                   mask[eth] = 0x08;
1488                   mask[eth + 1] = 0x00;
1489                 }
1490
1491               /* add session to table mvec[match_type_index].table_index; */
1492               vnet_classify_add_del_session (cm, tag_table,
1493                                              mask,
1494                                              a->rules[i].is_permit ? ~0 : 0,
1495                                              i, 0, action, metadata, 1);
1496               // clib_memset (&mask[12], 0, sizeof (mask) - 12);
1497             }
1498
1499           /* add ARP table entry too */
1500           if (!is6 && (mvec[match_type_index].out_arp_table_index != ~0))
1501             {
1502               for (tags = 2; tags >= 0; tags--)
1503                 {
1504                   clib_memset (mask, 0, sizeof (mask));
1505                   switch (tags)
1506                     {
1507                     case 0:
1508                     default:
1509                       tag_table = mvec[match_type_index].out_arp_table_index;
1510                       mask[12] = 0x08;
1511                       mask[13] = 0x06;
1512                       break;
1513                     case 1:
1514                       tag_table =
1515                         mvec[match_type_index].out_arp_dot1q_table_index;
1516                       mask[12] = 0x81;
1517                       mask[13] = 0x00;
1518                       mask[16] = 0x08;
1519                       mask[17] = 0x06;
1520                       break;
1521                     case 2:
1522                       tag_table =
1523                         mvec[match_type_index].out_arp_dot1ad_table_index;
1524                       mask[12] = 0x88;
1525                       mask[13] = 0xa8;
1526                       mask[16] = 0x81;
1527                       mask[17] = 0x00;
1528                       mask[20] = 0x08;
1529                       mask[21] = 0x06;
1530                       break;
1531                     }
1532
1533                   vnet_classify_add_del_session (cm, tag_table,
1534                                                  mask,
1535                                                  a->
1536                                                  rules[i].is_permit ? ~0 : 0,
1537                                                  i, 0, action, metadata, 1);
1538                 }
1539             }
1540         }
1541     }
1542   return 0;
1543 }
1544
1545 static void
1546 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1547 {
1548   vnet_classify_main_t *cm = &vnet_classify_main;
1549   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1550
1551   if (a->ip4_table_index != ~0)
1552     {
1553       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1554                                         &a->ip4_table_index, 0);
1555       a->ip4_table_index = ~0;
1556     }
1557   if (a->ip6_table_index != ~0)
1558     {
1559       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1560                                         &a->ip6_table_index, 0);
1561       a->ip6_table_index = ~0;
1562     }
1563   if (a->l2_table_index != ~0)
1564     {
1565       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index,
1566                                         0);
1567       a->l2_table_index = ~0;
1568     }
1569   if (a->out_ip4_table_index != ~0)
1570     {
1571       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1572                                         &a->out_ip4_table_index, 0);
1573       a->out_ip4_table_index = ~0;
1574     }
1575   if (a->out_ip6_table_index != ~0)
1576     {
1577       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1578                                         &a->out_ip6_table_index, 0);
1579       a->out_ip6_table_index = ~0;
1580     }
1581   if (a->out_l2_table_index != ~0)
1582     {
1583       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1584                                         &a->out_l2_table_index, 0);
1585       a->out_l2_table_index = ~0;
1586     }
1587 }
1588
1589 static int
1590 macip_maybe_apply_unapply_classifier_tables (acl_main_t * am, u32 acl_index,
1591                                              int is_apply)
1592 {
1593   int rv = 0;
1594   int rv0 = 0;
1595   int i;
1596   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, acl_index);
1597
1598   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1599     if (vec_elt (am->macip_acl_by_sw_if_index, i) == acl_index)
1600       {
1601         rv0 = vnet_set_input_acl_intfc (am->vlib_main, i, a->ip4_table_index,
1602                                         a->ip6_table_index, a->l2_table_index,
1603                                         is_apply);
1604         /* return the first unhappy outcome but make try to plough through. */
1605         rv = rv || rv0;
1606         rv0 =
1607           vnet_set_output_acl_intfc (am->vlib_main, i, a->out_ip4_table_index,
1608                                      a->out_ip6_table_index,
1609                                      a->out_l2_table_index, is_apply);
1610         /* return the first unhappy outcome but make try to plough through. */
1611         rv = rv || rv0;
1612       }
1613   return rv;
1614 }
1615
1616 static int
1617 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1618                     u32 * acl_list_index, u8 * tag)
1619 {
1620   acl_main_t *am = &acl_main;
1621   macip_acl_list_t *a;
1622   macip_acl_rule_t *r;
1623   macip_acl_rule_t *acl_new_rules = 0;
1624   int i;
1625   int rv = 0;
1626
1627   if (*acl_list_index != ~0)
1628     {
1629       /* They supplied some number, let's see if this MACIP ACL exists */
1630       if (pool_is_free_index (am->macip_acls, *acl_list_index))
1631         {
1632           /* tried to replace a non-existent ACL, no point doing anything */
1633           clib_warning
1634             ("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)",
1635              *acl_list_index, tag);
1636           return VNET_API_ERROR_NO_SUCH_ENTRY;
1637         }
1638     }
1639
1640   if (0 == count)
1641     {
1642       clib_warning
1643         ("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)",
1644          tag);
1645     }
1646   /* if replacing the ACL, unapply the classifier tables first - they will be gone.. */
1647   if (~0 != *acl_list_index)
1648     rv = macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 0);
1649   void *oldheap = acl_set_heap (am);
1650   /* Create and populate the rules */
1651   if (count > 0)
1652     vec_validate (acl_new_rules, count - 1);
1653
1654   for (i = 0; i < count; i++)
1655     {
1656       r = &acl_new_rules[i];
1657       r->is_permit = rules[i].is_permit;
1658       r->is_ipv6 = rules[i].is_ipv6;
1659       memcpy (&r->src_mac, rules[i].src_mac, 6);
1660       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1661       if (rules[i].is_ipv6)
1662         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1663       else
1664         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1665       r->src_prefixlen = rules[i].src_ip_prefix_len;
1666     }
1667
1668   if (~0 == *acl_list_index)
1669     {
1670       /* Get ACL index */
1671       pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1672       clib_memset (a, 0, sizeof (*a));
1673       /* Will return the newly allocated ACL index */
1674       *acl_list_index = a - am->macip_acls;
1675     }
1676   else
1677     {
1678       a = pool_elt_at_index (am->macip_acls, *acl_list_index);
1679       if (a->rules)
1680         {
1681           vec_free (a->rules);
1682         }
1683       macip_destroy_classify_tables (am, *acl_list_index);
1684     }
1685
1686   a->rules = acl_new_rules;
1687   a->count = count;
1688   memcpy (a->tag, tag, sizeof (a->tag));
1689
1690   /* Create and populate the classifier tables */
1691   macip_create_classify_tables (am, *acl_list_index);
1692   clib_mem_set_heap (oldheap);
1693   /* If the ACL was already applied somewhere, reapply the newly created tables */
1694   rv = rv
1695     || macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 1);
1696   return rv;
1697 }
1698
1699 /* No check that sw_if_index denotes a valid interface - the callers
1700  * were supposed to validate.
1701  *
1702  * That said, if sw_if_index corresponds to an interface that exists at all,
1703  * this function must return errors accordingly if the ACL is not applied.
1704  */
1705
1706 static int
1707 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1708 {
1709   int rv;
1710   u32 macip_acl_index;
1711   macip_acl_list_t *a;
1712
1713   /* The vector is too short - MACIP ACL is not applied */
1714   if (sw_if_index >= vec_len (am->macip_acl_by_sw_if_index))
1715     return VNET_API_ERROR_NO_SUCH_ENTRY;
1716
1717   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1718   /* No point in deleting MACIP ACL which is not applied */
1719   if (~0 == macip_acl_index)
1720     return VNET_API_ERROR_NO_SUCH_ENTRY;
1721
1722   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1723   /* remove the classifier tables off the interface L2 ACL */
1724   rv =
1725     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1726                               a->ip6_table_index, a->l2_table_index, 0);
1727   rv |=
1728     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
1729                                a->out_ip4_table_index, a->out_ip6_table_index,
1730                                a->out_l2_table_index, 0);
1731   /* Unset the MACIP ACL index */
1732   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1733   /* macip_acl_interface_add_acl did a vec_add1() to this previously, so [sw_if_index] should be valid */
1734   u32 index = vec_search (am->sw_if_index_vec_by_macip_acl[macip_acl_index],
1735                           sw_if_index);
1736   if (index != ~0)
1737     vec_del1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], index);
1738   return rv;
1739 }
1740
1741 /* No check for validity of sw_if_index - the callers were supposed to validate */
1742
1743 static int
1744 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1745                              u32 macip_acl_index)
1746 {
1747   macip_acl_list_t *a;
1748   int rv;
1749   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1750     {
1751       return VNET_API_ERROR_NO_SUCH_ENTRY;
1752     }
1753   void *oldheap = acl_set_heap (am);
1754   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1755   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1756   vec_validate (am->sw_if_index_vec_by_macip_acl, macip_acl_index);
1757   vec_add1 (am->sw_if_index_vec_by_macip_acl[macip_acl_index], sw_if_index);
1758   clib_mem_set_heap (oldheap);
1759   /* If there already a MACIP ACL applied, unapply it */
1760   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1761     macip_acl_interface_del_acl (am, sw_if_index);
1762   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1763
1764   /* Apply the classifier tables for L2 ACLs */
1765   rv =
1766     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1767                               a->ip6_table_index, a->l2_table_index, 1);
1768   rv |=
1769     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
1770                                a->out_ip4_table_index, a->out_ip6_table_index,
1771                                a->out_l2_table_index, 1);
1772   return rv;
1773 }
1774
1775 static int
1776 macip_acl_del_list (u32 acl_list_index)
1777 {
1778   acl_main_t *am = &acl_main;
1779   macip_acl_list_t *a;
1780   int i;
1781   if (pool_is_free_index (am->macip_acls, acl_list_index))
1782     {
1783       return VNET_API_ERROR_NO_SUCH_ENTRY;
1784     }
1785
1786   /* delete any references to the ACL */
1787   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1788     {
1789       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1790         {
1791           macip_acl_interface_del_acl (am, i);
1792         }
1793     }
1794
1795   void *oldheap = acl_set_heap (am);
1796   /* Now that classifier tables are detached, clean them up */
1797   macip_destroy_classify_tables (am, acl_list_index);
1798
1799   /* now we can delete the ACL itself */
1800   a = pool_elt_at_index (am->macip_acls, acl_list_index);
1801   if (a->rules)
1802     {
1803       vec_free (a->rules);
1804     }
1805   pool_put (am->macip_acls, a);
1806   clib_mem_set_heap (oldheap);
1807   return 0;
1808 }
1809
1810
1811 static int
1812 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1813                                  u32 acl_list_index)
1814 {
1815   acl_main_t *am = &acl_main;
1816   int rv = -1;
1817   if (is_add)
1818     {
1819       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1820     }
1821   else
1822     {
1823       rv = macip_acl_interface_del_acl (am, sw_if_index);
1824     }
1825   return rv;
1826 }
1827
1828 /*
1829  * If the client does not allocate enough memory for a variable-length
1830  * message, and then proceed to use it as if the full memory allocated,
1831  * absent the check we happily consume that on the VPP side, and go
1832  * along as if nothing happened. However, the resulting
1833  * effects range from just garbage in the API decode
1834  * (because the decoder snoops too far), to potential memory
1835  * corruptions.
1836  *
1837  * This verifies that the actual length of the message is
1838  * at least expected_len, and complains loudly if it is not.
1839  *
1840  * A failing check here is 100% a software bug on the API user side,
1841  * so we might as well yell.
1842  *
1843  */
1844 static int
1845 verify_message_len (void *mp, u32 expected_len, char *where)
1846 {
1847   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1848   if (supplied_len < expected_len)
1849     {
1850       clib_warning ("%s: Supplied message length %d is less than expected %d",
1851                     where, supplied_len, expected_len);
1852       return 0;
1853     }
1854   else
1855     {
1856       return 1;
1857     }
1858 }
1859
1860 /* API message handler */
1861 static void
1862 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1863 {
1864   vl_api_acl_add_replace_reply_t *rmp;
1865   acl_main_t *am = &acl_main;
1866   int rv;
1867   u32 acl_list_index = ntohl (mp->acl_index);
1868   u32 acl_count = ntohl (mp->count);
1869   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
1870
1871   if (verify_message_len (mp, expected_len, "acl_add_replace"))
1872     {
1873       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1874     }
1875   else
1876     {
1877       rv = VNET_API_ERROR_INVALID_VALUE;
1878     }
1879
1880   /* *INDENT-OFF* */
1881   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1882   ({
1883     rmp->acl_index = htonl(acl_list_index);
1884   }));
1885   /* *INDENT-ON* */
1886 }
1887
1888 static void
1889 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1890 {
1891   acl_main_t *am = &acl_main;
1892   vl_api_acl_del_reply_t *rmp;
1893   int rv;
1894
1895   rv = acl_del_list (ntohl (mp->acl_index));
1896
1897   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1898 }
1899
1900 static void
1901 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1902 {
1903   acl_main_t *am = &acl_main;
1904   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1905   u32 sw_if_index = ntohl (mp->sw_if_index);
1906   vl_api_acl_interface_add_del_reply_t *rmp;
1907   int rv = -1;
1908
1909   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
1910     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1911   else
1912     rv =
1913       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1914                                        mp->is_input, ntohl (mp->acl_index));
1915
1916   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1917 }
1918
1919 static void
1920   vl_api_acl_interface_set_acl_list_t_handler
1921   (vl_api_acl_interface_set_acl_list_t * mp)
1922 {
1923   acl_main_t *am = &acl_main;
1924   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1925   int rv = 0;
1926   int i;
1927   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1928   u32 sw_if_index = ntohl (mp->sw_if_index);
1929
1930   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
1931     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1932   else
1933     {
1934       int may_clear_sessions = 1;
1935       for (i = 0; i < mp->count; i++)
1936         {
1937           if (acl_is_not_defined (am, ntohl (mp->acls[i])))
1938             {
1939               /* ACL does not exist, so we can not apply it */
1940               rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1941             }
1942         }
1943       if (0 == rv)
1944         {
1945           void *oldheap = acl_set_heap (am);
1946
1947           u32 *in_acl_vec = 0;
1948           u32 *out_acl_vec = 0;
1949           for (i = 0; i < mp->count; i++)
1950             if (i < mp->n_input)
1951               vec_add1 (in_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
1952             else
1953               vec_add1 (out_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
1954
1955           rv =
1956             acl_interface_set_inout_acl_list (am, sw_if_index, 0, out_acl_vec,
1957                                               &may_clear_sessions);
1958           rv = rv
1959             || acl_interface_set_inout_acl_list (am, sw_if_index, 1,
1960                                                  in_acl_vec,
1961                                                  &may_clear_sessions);
1962           vec_free (in_acl_vec);
1963           vec_free (out_acl_vec);
1964           clib_mem_set_heap (oldheap);
1965         }
1966     }
1967
1968   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1969 }
1970
1971 static void
1972 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1973 {
1974   api_rule->is_permit = r->is_permit;
1975   api_rule->is_ipv6 = r->is_ipv6;
1976   if (r->is_ipv6)
1977     {
1978       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1979       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1980     }
1981   else
1982     {
1983       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1984       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1985     }
1986   api_rule->src_ip_prefix_len = r->src_prefixlen;
1987   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1988   api_rule->proto = r->proto;
1989   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1990   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1991   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1992   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1993   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1994   api_rule->tcp_flags_value = r->tcp_flags_value;
1995 }
1996
1997 static void
1998 send_acl_details (acl_main_t * am, vl_api_registration_t * reg,
1999                   acl_list_t * acl, u32 context)
2000 {
2001   vl_api_acl_details_t *mp;
2002   vl_api_acl_rule_t *rules;
2003   int i;
2004   acl_rule_t *acl_rules = acl->rules;
2005   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * vec_len (acl_rules);
2006   void *oldheap = acl_set_heap (am);
2007
2008   mp = vl_msg_api_alloc (msg_size);
2009   clib_memset (mp, 0, msg_size);
2010   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
2011
2012   /* fill in the message */
2013   mp->context = context;
2014   mp->count = htonl (vec_len (acl_rules));
2015   mp->acl_index = htonl (acl - am->acls);
2016   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2017   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
2018   rules = mp->r;
2019   for (i = 0; i < vec_len (acl_rules); i++)
2020     {
2021       copy_acl_rule_to_api_rule (&rules[i], &acl_rules[i]);
2022     }
2023
2024   clib_mem_set_heap (oldheap);
2025   vl_api_send_msg (reg, (u8 *) mp);
2026 }
2027
2028
2029 static void
2030 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
2031 {
2032   acl_main_t *am = &acl_main;
2033   u32 acl_index;
2034   acl_list_t *acl;
2035   int rv = -1;
2036   vl_api_registration_t *reg;
2037
2038   reg = vl_api_client_index_to_registration (mp->client_index);
2039   if (!reg)
2040     return;
2041
2042   if (mp->acl_index == ~0)
2043     {
2044     /* *INDENT-OFF* */
2045     /* Just dump all ACLs */
2046     pool_foreach (acl, am->acls,
2047     ({
2048       send_acl_details(am, reg, acl, mp->context);
2049     }));
2050     /* *INDENT-ON* */
2051     }
2052   else
2053     {
2054       acl_index = ntohl (mp->acl_index);
2055       if (!pool_is_free_index (am->acls, acl_index))
2056         {
2057           acl = pool_elt_at_index (am->acls, acl_index);
2058           send_acl_details (am, reg, acl, mp->context);
2059         }
2060     }
2061
2062   if (rv == -1)
2063     {
2064       /* FIXME API: should we signal an error here at all ? */
2065       return;
2066     }
2067 }
2068
2069 static void
2070 send_acl_interface_list_details (acl_main_t * am,
2071                                  vl_api_registration_t * reg,
2072                                  u32 sw_if_index, u32 context)
2073 {
2074   vl_api_acl_interface_list_details_t *mp;
2075   int msg_size;
2076   int n_input;
2077   int n_output;
2078   int count;
2079   int i = 0;
2080   void *oldheap = acl_set_heap (am);
2081
2082   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
2083   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
2084
2085   clib_mem_set_heap (oldheap);
2086
2087   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
2088   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
2089   count = n_input + n_output;
2090
2091   msg_size = sizeof (*mp);
2092   msg_size += sizeof (mp->acls[0]) * count;
2093
2094   mp = vl_msg_api_alloc (msg_size);
2095   clib_memset (mp, 0, msg_size);
2096   mp->_vl_msg_id =
2097     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2098
2099   /* fill in the message */
2100   mp->context = context;
2101   mp->sw_if_index = htonl (sw_if_index);
2102   mp->count = count;
2103   mp->n_input = n_input;
2104   for (i = 0; i < n_input; i++)
2105     {
2106       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
2107     }
2108   for (i = 0; i < n_output; i++)
2109     {
2110       mp->acls[n_input + i] =
2111         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
2112     }
2113   vl_api_send_msg (reg, (u8 *) mp);
2114 }
2115
2116 static void
2117 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
2118                                           mp)
2119 {
2120   acl_main_t *am = &acl_main;
2121   vnet_sw_interface_t *swif;
2122   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2123
2124   u32 sw_if_index;
2125   vl_api_registration_t *reg;
2126
2127   reg = vl_api_client_index_to_registration (mp->client_index);
2128   if (!reg)
2129     return;
2130
2131   if (mp->sw_if_index == ~0)
2132     {
2133     /* *INDENT-OFF* */
2134     pool_foreach (swif, im->sw_interfaces,
2135     ({
2136       send_acl_interface_list_details(am, reg, swif->sw_if_index, mp->context);
2137     }));
2138     /* *INDENT-ON* */
2139     }
2140   else
2141     {
2142       sw_if_index = ntohl (mp->sw_if_index);
2143       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2144         send_acl_interface_list_details (am, reg, sw_if_index, mp->context);
2145     }
2146 }
2147
2148 /* MACIP ACL API handlers */
2149
2150 static void
2151 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
2152 {
2153   vl_api_macip_acl_add_reply_t *rmp;
2154   acl_main_t *am = &acl_main;
2155   int rv;
2156   u32 acl_list_index = ~0;
2157   u32 acl_count = ntohl (mp->count);
2158   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2159
2160   if (verify_message_len (mp, expected_len, "macip_acl_add"))
2161     {
2162       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2163     }
2164   else
2165     {
2166       rv = VNET_API_ERROR_INVALID_VALUE;
2167     }
2168
2169   /* *INDENT-OFF* */
2170   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
2171   ({
2172     rmp->acl_index = htonl(acl_list_index);
2173   }));
2174   /* *INDENT-ON* */
2175 }
2176
2177 static void
2178 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
2179 {
2180   vl_api_macip_acl_add_replace_reply_t *rmp;
2181   acl_main_t *am = &acl_main;
2182   int rv;
2183   u32 acl_list_index = ntohl (mp->acl_index);
2184   u32 acl_count = ntohl (mp->count);
2185   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2186
2187   if (verify_message_len (mp, expected_len, "macip_acl_add_replace"))
2188     {
2189       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2190     }
2191   else
2192     {
2193       rv = VNET_API_ERROR_INVALID_VALUE;
2194     }
2195
2196   /* *INDENT-OFF* */
2197   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
2198   ({
2199     rmp->acl_index = htonl(acl_list_index);
2200   }));
2201   /* *INDENT-ON* */
2202 }
2203
2204 static void
2205 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
2206 {
2207   acl_main_t *am = &acl_main;
2208   vl_api_macip_acl_del_reply_t *rmp;
2209   int rv;
2210
2211   rv = macip_acl_del_list (ntohl (mp->acl_index));
2212
2213   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
2214 }
2215
2216 static void
2217   vl_api_macip_acl_interface_add_del_t_handler
2218   (vl_api_macip_acl_interface_add_del_t * mp)
2219 {
2220   acl_main_t *am = &acl_main;
2221   vl_api_macip_acl_interface_add_del_reply_t *rmp;
2222   int rv = -1;
2223   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2224   u32 sw_if_index = ntohl (mp->sw_if_index);
2225
2226   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2227     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2228   else
2229     rv =
2230       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
2231                                        ntohl (mp->acl_index));
2232
2233   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
2234 }
2235
2236 static void
2237 send_macip_acl_details (acl_main_t * am, vl_api_registration_t * reg,
2238                         macip_acl_list_t * acl, u32 context)
2239 {
2240   vl_api_macip_acl_details_t *mp;
2241   vl_api_macip_acl_rule_t *rules;
2242   macip_acl_rule_t *r;
2243   int i;
2244   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
2245
2246   mp = vl_msg_api_alloc (msg_size);
2247   clib_memset (mp, 0, msg_size);
2248   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
2249
2250   /* fill in the message */
2251   mp->context = context;
2252   if (acl)
2253     {
2254       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2255       mp->count = htonl (acl->count);
2256       mp->acl_index = htonl (acl - am->macip_acls);
2257       rules = mp->r;
2258       for (i = 0; i < acl->count; i++)
2259         {
2260           r = &acl->rules[i];
2261           rules[i].is_permit = r->is_permit;
2262           rules[i].is_ipv6 = r->is_ipv6;
2263           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
2264           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
2265                   sizeof (r->src_mac_mask));
2266           if (r->is_ipv6)
2267             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
2268                     sizeof (r->src_ip_addr.ip6));
2269           else
2270             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
2271                     sizeof (r->src_ip_addr.ip4));
2272           rules[i].src_ip_prefix_len = r->src_prefixlen;
2273         }
2274     }
2275   else
2276     {
2277       /* No martini, no party - no ACL applied to this interface. */
2278       mp->acl_index = ~0;
2279       mp->count = 0;
2280     }
2281
2282   vl_api_send_msg (reg, (u8 *) mp);
2283 }
2284
2285
2286 static void
2287 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
2288 {
2289   acl_main_t *am = &acl_main;
2290   macip_acl_list_t *acl;
2291
2292   vl_api_registration_t *reg;
2293
2294   reg = vl_api_client_index_to_registration (mp->client_index);
2295   if (!reg)
2296     return;
2297
2298   if (mp->acl_index == ~0)
2299     {
2300       /* Just dump all ACLs for now, with sw_if_index = ~0 */
2301       pool_foreach (acl, am->macip_acls, (
2302                                            {
2303                                            send_macip_acl_details (am, reg,
2304                                                                    acl,
2305                                                                    mp->context);
2306                                            }
2307                     ));
2308       /* *INDENT-ON* */
2309     }
2310   else
2311     {
2312       u32 acl_index = ntohl (mp->acl_index);
2313       if (!pool_is_free_index (am->macip_acls, acl_index))
2314         {
2315           acl = pool_elt_at_index (am->macip_acls, acl_index);
2316           send_macip_acl_details (am, reg, acl, mp->context);
2317         }
2318     }
2319 }
2320
2321 static void
2322 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
2323                                           mp)
2324 {
2325   acl_main_t *am = &acl_main;
2326   vl_api_macip_acl_interface_get_reply_t *rmp;
2327   u32 count = vec_len (am->macip_acl_by_sw_if_index);
2328   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
2329   vl_api_registration_t *reg;
2330   int i;
2331
2332   reg = vl_api_client_index_to_registration (mp->client_index);
2333   if (!reg)
2334     return;
2335
2336   rmp = vl_msg_api_alloc (msg_size);
2337   clib_memset (rmp, 0, msg_size);
2338   rmp->_vl_msg_id =
2339     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
2340   rmp->context = mp->context;
2341   rmp->count = htonl (count);
2342   for (i = 0; i < count; i++)
2343     {
2344       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
2345     }
2346
2347   vl_api_send_msg (reg, (u8 *) rmp);
2348 }
2349
2350 static void
2351 send_macip_acl_interface_list_details (acl_main_t * am,
2352                                        vl_api_registration_t * reg,
2353                                        u32 sw_if_index,
2354                                        u32 acl_index, u32 context)
2355 {
2356   vl_api_macip_acl_interface_list_details_t *rmp;
2357   /* at this time there is only ever 1 mac ip acl per interface */
2358   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
2359
2360   rmp = vl_msg_api_alloc (msg_size);
2361   clib_memset (rmp, 0, msg_size);
2362   rmp->_vl_msg_id =
2363     ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2364
2365   /* fill in the message */
2366   rmp->context = context;
2367   rmp->count = 1;
2368   rmp->sw_if_index = htonl (sw_if_index);
2369   rmp->acls[0] = htonl (acl_index);
2370
2371   vl_api_send_msg (reg, (u8 *) rmp);
2372 }
2373
2374 static void
2375   vl_api_macip_acl_interface_list_dump_t_handler
2376   (vl_api_macip_acl_interface_list_dump_t * mp)
2377 {
2378   vl_api_registration_t *reg;
2379   acl_main_t *am = &acl_main;
2380   u32 sw_if_index = ntohl (mp->sw_if_index);
2381
2382   reg = vl_api_client_index_to_registration (mp->client_index);
2383   if (!reg)
2384     return;
2385
2386   if (sw_if_index == ~0)
2387     {
2388       vec_foreach_index (sw_if_index, am->macip_acl_by_sw_if_index)
2389       {
2390         if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2391           {
2392             send_macip_acl_interface_list_details (am, reg, sw_if_index,
2393                                                    am->macip_acl_by_sw_if_index
2394                                                    [sw_if_index],
2395                                                    mp->context);
2396           }
2397       }
2398     }
2399   else
2400     {
2401       if (vec_len (am->macip_acl_by_sw_if_index) > sw_if_index)
2402         {
2403           send_macip_acl_interface_list_details (am, reg, sw_if_index,
2404                                                  am->macip_acl_by_sw_if_index
2405                                                  [sw_if_index], mp->context);
2406         }
2407     }
2408 }
2409
2410 static void
2411   vl_api_acl_interface_set_etype_whitelist_t_handler
2412   (vl_api_acl_interface_set_etype_whitelist_t * mp)
2413 {
2414   acl_main_t *am = &acl_main;
2415   vl_api_acl_interface_set_etype_whitelist_reply_t *rmp;
2416   int rv = 0;
2417   int i;
2418   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2419   u32 sw_if_index = ntohl (mp->sw_if_index);
2420   u16 *vec_in = 0, *vec_out = 0;
2421   void *oldheap = acl_set_heap (am);
2422
2423   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2424     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2425   else
2426     {
2427       for (i = 0; i < mp->count; i++)
2428         {
2429           if (i < mp->n_input)
2430             vec_add1 (vec_in, ntohs (mp->whitelist[i]));
2431           else
2432             vec_add1 (vec_out, ntohs (mp->whitelist[i]));
2433         }
2434       rv = acl_set_etype_whitelists (am, sw_if_index, vec_in, vec_out);
2435     }
2436
2437   clib_mem_set_heap (oldheap);
2438   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY);
2439 }
2440
2441 static void
2442 send_acl_interface_etype_whitelist_details (acl_main_t * am,
2443                                             vl_api_registration_t * reg,
2444                                             u32 sw_if_index, u32 context)
2445 {
2446   vl_api_acl_interface_etype_whitelist_details_t *mp;
2447   int msg_size;
2448   int n_input = 0;
2449   int n_output = 0;
2450   int count = 0;
2451   int i = 0;
2452
2453   u16 *whitelist_in = 0;
2454   u16 *whitelist_out = 0;
2455
2456   if (intf_has_etype_whitelist (am, sw_if_index, 0))
2457     whitelist_out =
2458       vec_elt (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
2459
2460   if (intf_has_etype_whitelist (am, sw_if_index, 1))
2461     whitelist_in =
2462       vec_elt (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
2463
2464   if ((0 == whitelist_in) && (0 == whitelist_out))
2465     return;                     /* nothing to do */
2466
2467   void *oldheap = acl_set_heap (am);
2468
2469   n_input = vec_len (whitelist_in);
2470   n_output = vec_len (whitelist_out);
2471   count = n_input + n_output;
2472
2473   msg_size = sizeof (*mp);
2474   msg_size += sizeof (mp->whitelist[0]) * count;
2475
2476   mp = vl_msg_api_alloc (msg_size);
2477   clib_memset (mp, 0, msg_size);
2478   mp->_vl_msg_id =
2479     ntohs (VL_API_ACL_INTERFACE_ETYPE_WHITELIST_DETAILS + am->msg_id_base);
2480
2481   /* fill in the message */
2482   mp->context = context;
2483   mp->sw_if_index = htonl (sw_if_index);
2484   mp->count = count;
2485   mp->n_input = n_input;
2486   for (i = 0; i < n_input; i++)
2487     {
2488       mp->whitelist[i] = htons (whitelist_in[i]);
2489     }
2490   for (i = 0; i < n_output; i++)
2491     {
2492       mp->whitelist[n_input + i] = htons (whitelist_out[i]);
2493     }
2494   clib_mem_set_heap (oldheap);
2495   vl_api_send_msg (reg, (u8 *) mp);
2496 }
2497
2498
2499 static void
2500   vl_api_acl_interface_etype_whitelist_dump_t_handler
2501   (vl_api_acl_interface_list_dump_t * mp)
2502 {
2503   acl_main_t *am = &acl_main;
2504   vnet_sw_interface_t *swif;
2505   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2506
2507   u32 sw_if_index;
2508   vl_api_registration_t *reg;
2509
2510   reg = vl_api_client_index_to_registration (mp->client_index);
2511   if (!reg)
2512     return;
2513
2514   if (mp->sw_if_index == ~0)
2515     {
2516     /* *INDENT-OFF* */
2517     pool_foreach (swif, im->sw_interfaces,
2518     ({
2519       send_acl_interface_etype_whitelist_details(am, reg, swif->sw_if_index, mp->context);
2520     }));
2521     /* *INDENT-ON* */
2522     }
2523   else
2524     {
2525       sw_if_index = ntohl (mp->sw_if_index);
2526       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2527         send_acl_interface_etype_whitelist_details (am, reg, sw_if_index,
2528                                                     mp->context);
2529     }
2530 }
2531
2532
2533
2534 /* Set up the API message handling tables */
2535 static clib_error_t *
2536 acl_plugin_api_hookup (vlib_main_t * vm)
2537 {
2538   acl_main_t *am = &acl_main;
2539 #define _(N,n)                                                  \
2540     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
2541                            #n,                                  \
2542                            vl_api_##n##_t_handler,              \
2543                            vl_noop_handler,                     \
2544                            vl_api_##n##_t_endian,               \
2545                            vl_api_##n##_t_print,                \
2546                            sizeof(vl_api_##n##_t), 1);
2547   foreach_acl_plugin_api_msg;
2548 #undef _
2549
2550   return 0;
2551 }
2552
2553 #define vl_msg_name_crc_list
2554 #include <acl/acl_all_api_h.h>
2555 #undef vl_msg_name_crc_list
2556
2557 static void
2558 setup_message_id_table (acl_main_t * am, api_main_t * apim)
2559 {
2560 #define _(id,n,crc) \
2561   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
2562   foreach_vl_msg_name_crc_acl;
2563 #undef _
2564 }
2565
2566 static void
2567 acl_set_timeout_sec (int timeout_type, u32 value)
2568 {
2569   acl_main_t *am = &acl_main;
2570   clib_time_t *ct = &am->vlib_main->clib_time;
2571
2572   if (timeout_type < ACL_N_TIMEOUTS)
2573     {
2574       am->session_timeout_sec[timeout_type] = value;
2575     }
2576   else
2577     {
2578       clib_warning ("Unknown timeout type %d", timeout_type);
2579       return;
2580     }
2581   am->session_timeout[timeout_type] =
2582     (u64) (((f64) value) / ct->seconds_per_clock);
2583 }
2584
2585 static void
2586 acl_set_session_max_entries (u32 value)
2587 {
2588   acl_main_t *am = &acl_main;
2589   am->fa_conn_table_max_entries = value;
2590 }
2591
2592 static int
2593 acl_set_skip_ipv6_eh (u32 eh, u32 value)
2594 {
2595   acl_main_t *am = &acl_main;
2596
2597   if ((eh < 256) && (value < 2))
2598     {
2599       am->fa_ipv6_known_eh_bitmap =
2600         clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
2601       return 1;
2602     }
2603   else
2604     return 0;
2605 }
2606
2607
2608 static clib_error_t *
2609 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
2610 {
2611   acl_main_t *am = &acl_main;
2612   if (0 == am->acl_mheap)
2613     {
2614       /* ACL heap is not initialized, so definitely nothing to do. */
2615       return 0;
2616     }
2617   if (0 == is_add)
2618     {
2619       int may_clear_sessions = 1;
2620       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2621                                  ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
2622                                  sw_if_index);
2623       /* also unapply any ACLs in case the users did not do so. */
2624       macip_acl_interface_del_acl (am, sw_if_index);
2625       acl_interface_reset_inout_acls (sw_if_index, 0, &may_clear_sessions);
2626       acl_interface_reset_inout_acls (sw_if_index, 1, &may_clear_sessions);
2627     }
2628   return 0;
2629 }
2630
2631 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
2632
2633
2634
2635 static clib_error_t *
2636 acl_set_aclplugin_fn (vlib_main_t * vm,
2637                       unformat_input_t * input, vlib_cli_command_t * cmd)
2638 {
2639   clib_error_t *error = 0;
2640   u32 timeout = 0;
2641   u32 val = 0;
2642   u32 eh_val = 0;
2643   uword memory_size = 0;
2644   acl_main_t *am = &acl_main;
2645
2646   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
2647     {
2648       if (!acl_set_skip_ipv6_eh (eh_val, val))
2649         {
2650           error = clib_error_return (0, "expecting eh=0..255, value=0..1");
2651         }
2652       goto done;
2653     }
2654   if (unformat (input, "use-hash-acl-matching %u", &val))
2655     {
2656       am->use_hash_acl_matching = (val != 0);
2657       goto done;
2658     }
2659   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
2660     {
2661       am->l4_match_nonfirst_fragment = (val != 0);
2662       goto done;
2663     }
2664   if (unformat (input, "reclassify-sessions %u", &val))
2665     {
2666       am->reclassify_sessions = (val != 0);
2667       goto done;
2668     }
2669   if (unformat (input, "event-trace"))
2670     {
2671       if (!unformat (input, "%u", &val))
2672         {
2673           error = clib_error_return (0,
2674                                      "expecting trace level, got `%U`",
2675                                      format_unformat_error, input);
2676           goto done;
2677         }
2678       else
2679         {
2680           am->trace_acl = val;
2681           goto done;
2682         }
2683     }
2684   if (unformat (input, "heap"))
2685     {
2686       if (unformat (input, "main"))
2687         {
2688           if (unformat (input, "validate %u", &val))
2689             acl_plugin_acl_set_validate_heap (am, val);
2690           else if (unformat (input, "trace %u", &val))
2691             acl_plugin_acl_set_trace_heap (am, val);
2692           goto done;
2693         }
2694       else if (unformat (input, "hash"))
2695         {
2696           if (unformat (input, "validate %u", &val))
2697             acl_plugin_hash_acl_set_validate_heap (val);
2698           else if (unformat (input, "trace %u", &val))
2699             acl_plugin_hash_acl_set_trace_heap (val);
2700           goto done;
2701         }
2702       goto done;
2703     }
2704   if (unformat (input, "session"))
2705     {
2706       if (unformat (input, "table"))
2707         {
2708           /* The commands here are for tuning/testing. No user-serviceable parts inside */
2709           if (unformat (input, "max-entries"))
2710             {
2711               if (!unformat (input, "%u", &val))
2712                 {
2713                   error = clib_error_return (0,
2714                                              "expecting maximum number of entries, got `%U`",
2715                                              format_unformat_error, input);
2716                   goto done;
2717                 }
2718               else
2719                 {
2720                   acl_set_session_max_entries (val);
2721                   goto done;
2722                 }
2723             }
2724           if (unformat (input, "hash-table-buckets"))
2725             {
2726               if (!unformat (input, "%u", &val))
2727                 {
2728                   error = clib_error_return (0,
2729                                              "expecting maximum number of hash table buckets, got `%U`",
2730                                              format_unformat_error, input);
2731                   goto done;
2732                 }
2733               else
2734                 {
2735                   am->fa_conn_table_hash_num_buckets = val;
2736                   goto done;
2737                 }
2738             }
2739           if (unformat (input, "hash-table-memory"))
2740             {
2741               if (!unformat (input, "%U", unformat_memory_size, &memory_size))
2742                 {
2743                   error = clib_error_return (0,
2744                                              "expecting maximum amount of hash table memory, got `%U`",
2745                                              format_unformat_error, input);
2746                   goto done;
2747                 }
2748               else
2749                 {
2750                   am->fa_conn_table_hash_memory_size = memory_size;
2751                   goto done;
2752                 }
2753             }
2754           if (unformat (input, "event-trace"))
2755             {
2756               if (!unformat (input, "%u", &val))
2757                 {
2758                   error = clib_error_return (0,
2759                                              "expecting trace level, got `%U`",
2760                                              format_unformat_error, input);
2761                   goto done;
2762                 }
2763               else
2764                 {
2765                   am->trace_sessions = val;
2766                   goto done;
2767                 }
2768             }
2769           goto done;
2770         }
2771       if (unformat (input, "timeout"))
2772         {
2773           if (unformat (input, "udp"))
2774             {
2775               if (unformat (input, "idle"))
2776                 {
2777                   if (!unformat (input, "%u", &timeout))
2778                     {
2779                       error = clib_error_return (0,
2780                                                  "expecting timeout value in seconds, got `%U`",
2781                                                  format_unformat_error,
2782                                                  input);
2783                       goto done;
2784                     }
2785                   else
2786                     {
2787                       acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
2788                       goto done;
2789                     }
2790                 }
2791             }
2792           if (unformat (input, "tcp"))
2793             {
2794               if (unformat (input, "idle"))
2795                 {
2796                   if (!unformat (input, "%u", &timeout))
2797                     {
2798                       error = clib_error_return (0,
2799                                                  "expecting timeout value in seconds, got `%U`",
2800                                                  format_unformat_error,
2801                                                  input);
2802                       goto done;
2803                     }
2804                   else
2805                     {
2806                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
2807                       goto done;
2808                     }
2809                 }
2810               if (unformat (input, "transient"))
2811                 {
2812                   if (!unformat (input, "%u", &timeout))
2813                     {
2814                       error = clib_error_return (0,
2815                                                  "expecting timeout value in seconds, got `%U`",
2816                                                  format_unformat_error,
2817                                                  input);
2818                       goto done;
2819                     }
2820                   else
2821                     {
2822                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
2823                                            timeout);
2824                       goto done;
2825                     }
2826                 }
2827             }
2828           goto done;
2829         }
2830     }
2831 done:
2832   return error;
2833 }
2834
2835 static u8 *
2836 my_format_mac_address (u8 * s, va_list * args)
2837 {
2838   u8 *a = va_arg (*args, u8 *);
2839   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
2840                  a[0], a[1], a[2], a[3], a[4], a[5]);
2841 }
2842
2843 static inline u8 *
2844 my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
2845 {
2846   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
2847
2848   out = format (out, "%s action %d ip %U/%d mac %U mask %U",
2849                 a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
2850                 format_ip46_address, &a->src_ip_addr,
2851                 a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
2852                 a->src_prefixlen,
2853                 my_format_mac_address, a->src_mac,
2854                 my_format_mac_address, a->src_mac_mask);
2855   return (out);
2856 }
2857
2858 static void
2859 macip_acl_print (acl_main_t * am, u32 macip_acl_index)
2860 {
2861   vlib_main_t *vm = am->vlib_main;
2862   int i;
2863
2864   /* Don't try to print someone else's memory */
2865   if (macip_acl_index >= vec_len (am->macip_acls))
2866     return;
2867
2868   macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
2869   int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
2870
2871   vlib_cli_output (vm,
2872                    "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
2873                    macip_acl_index, a->count, vec_len (a->rules), a->tag,
2874                    free_pool_slot);
2875   vlib_cli_output (vm,
2876                    "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
2877                    a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
2878   vlib_cli_output (vm,
2879                    "  out_ip4_table_index %d, out_ip6_table_index %d, out_l2_table_index %d\n",
2880                    a->out_ip4_table_index, a->out_ip6_table_index,
2881                    a->out_l2_table_index);
2882   for (i = 0; i < vec_len (a->rules); i++)
2883     vlib_cli_output (vm, "    rule %d: %U\n", i,
2884                      my_macip_acl_rule_t_pretty_format,
2885                      vec_elt_at_index (a->rules, i));
2886
2887 }
2888
2889 static clib_error_t *
2890 acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
2891                                  unformat_input_t *
2892                                  input, vlib_cli_command_t * cmd)
2893 {
2894   clib_error_t *error = 0;
2895   acl_main_t *am = &acl_main;
2896   int i;
2897   u32 acl_index = ~0;
2898
2899   (void) unformat (input, "index %u", &acl_index);
2900
2901   for (i = 0; i < vec_len (am->macip_acls); i++)
2902     {
2903       /* Don't attempt to show the ACLs that do not exist */
2904       if (pool_is_free_index (am->macip_acls, i))
2905         continue;
2906
2907       if ((acl_index != ~0) && (acl_index != i))
2908         {
2909           continue;
2910         }
2911
2912       macip_acl_print (am, i);
2913       if (i < vec_len (am->sw_if_index_vec_by_macip_acl))
2914         {
2915           vlib_cli_output (vm, "  applied on sw_if_index(s): %U\n",
2916                            format_vec32,
2917                            vec_elt (am->sw_if_index_vec_by_macip_acl, i),
2918                            "%d");
2919         }
2920     }
2921
2922   return error;
2923 }
2924
2925 static clib_error_t *
2926 acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
2927                                        unformat_input_t *
2928                                        input, vlib_cli_command_t * cmd)
2929 {
2930   clib_error_t *error = 0;
2931   acl_main_t *am = &acl_main;
2932   int i;
2933   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
2934     {
2935       vlib_cli_output (vm, "  sw_if_index %d: %d\n", i,
2936                        vec_elt (am->macip_acl_by_sw_if_index, i));
2937     }
2938   return error;
2939 }
2940
2941 static void
2942 acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
2943 {
2944   u32 i;
2945   vlib_main_t *vm = am->vlib_main;
2946
2947   for (i = 0; i < vec_len (am->acls); i++)
2948     {
2949       if (acl_is_not_defined (am, i))
2950         {
2951           /* don't attempt to show the ACLs that do not exist */
2952           continue;
2953         }
2954       if ((acl_index != ~0) && (acl_index != i))
2955         {
2956           continue;
2957         }
2958       acl_print_acl (vm, am, i);
2959
2960       if (i < vec_len (am->input_sw_if_index_vec_by_acl))
2961         {
2962           vlib_cli_output (vm, "  applied inbound on sw_if_index: %U\n",
2963                            format_vec32, am->input_sw_if_index_vec_by_acl[i],
2964                            "%d");
2965         }
2966       if (i < vec_len (am->output_sw_if_index_vec_by_acl))
2967         {
2968           vlib_cli_output (vm, "  applied outbound on sw_if_index: %U\n",
2969                            format_vec32, am->output_sw_if_index_vec_by_acl[i],
2970                            "%d");
2971         }
2972       if (i < vec_len (am->lc_index_vec_by_acl))
2973         {
2974           vlib_cli_output (vm, "  used in lookup context index: %U\n",
2975                            format_vec32, am->lc_index_vec_by_acl[i], "%d");
2976         }
2977     }
2978 }
2979
2980 static clib_error_t *
2981 acl_show_aclplugin_acl_fn (vlib_main_t * vm,
2982                            unformat_input_t * input, vlib_cli_command_t * cmd)
2983 {
2984   clib_error_t *error = 0;
2985   acl_main_t *am = &acl_main;
2986
2987   u32 acl_index = ~0;
2988   (void) unformat (input, "index %u", &acl_index);
2989
2990   acl_plugin_show_acl (am, acl_index);
2991   return error;
2992 }
2993
2994 static clib_error_t *
2995 acl_show_aclplugin_lookup_context_fn (vlib_main_t * vm,
2996                                       unformat_input_t * input,
2997                                       vlib_cli_command_t * cmd)
2998 {
2999   clib_error_t *error = 0;
3000
3001   u32 lc_index = ~0;
3002   (void) unformat (input, "index %u", &lc_index);
3003
3004   acl_plugin_show_lookup_context (lc_index);
3005   return error;
3006 }
3007
3008 static clib_error_t *
3009 acl_show_aclplugin_lookup_user_fn (vlib_main_t * vm,
3010                                    unformat_input_t * input,
3011                                    vlib_cli_command_t * cmd)
3012 {
3013   clib_error_t *error = 0;
3014
3015   u32 lc_index = ~0;
3016   (void) unformat (input, "index %u", &lc_index);
3017
3018   acl_plugin_show_lookup_user (lc_index);
3019   return error;
3020 }
3021
3022
3023 static void
3024 acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl,
3025                            int detail)
3026 {
3027   vlib_main_t *vm = am->vlib_main;
3028   u32 swi;
3029   u32 *pj;
3030   for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
3031        (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
3032     {
3033       /* if we need a particular interface, skip all the others */
3034       if ((sw_if_index != ~0) && (sw_if_index != swi))
3035         continue;
3036
3037       vlib_cli_output (vm, "sw_if_index %d:\n", swi);
3038       if (swi < vec_len (am->input_policy_epoch_by_sw_if_index))
3039         vlib_cli_output (vm, "   input policy epoch: %x\n",
3040                          vec_elt (am->input_policy_epoch_by_sw_if_index,
3041                                   swi));
3042       if (swi < vec_len (am->output_policy_epoch_by_sw_if_index))
3043         vlib_cli_output (vm, "   output policy epoch: %x\n",
3044                          vec_elt (am->output_policy_epoch_by_sw_if_index,
3045                                   swi));
3046
3047
3048       if (intf_has_etype_whitelist (am, swi, 1))
3049         {
3050           vlib_cli_output (vm, "  input etype whitelist: %U", format_vec16,
3051                            am->input_etype_whitelist_by_sw_if_index[swi],
3052                            "%04x");
3053         }
3054       if (intf_has_etype_whitelist (am, swi, 0))
3055         {
3056           vlib_cli_output (vm, " output etype whitelist: %U", format_vec16,
3057                            am->output_etype_whitelist_by_sw_if_index[swi],
3058                            "%04x");
3059         }
3060
3061       if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
3062           (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
3063         {
3064           vlib_cli_output (vm, "  input acl(s): %U", format_vec32,
3065                            am->input_acl_vec_by_sw_if_index[swi], "%d");
3066           if (show_acl)
3067             {
3068               vlib_cli_output (vm, "\n");
3069               vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
3070               {
3071                 acl_print_acl (vm, am, *pj);
3072               }
3073               vlib_cli_output (vm, "\n");
3074             }
3075         }
3076
3077       if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
3078           (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
3079         {
3080           vlib_cli_output (vm, "  output acl(s): %U", format_vec32,
3081                            am->output_acl_vec_by_sw_if_index[swi], "%d");
3082           if (show_acl)
3083             {
3084               vlib_cli_output (vm, "\n");
3085               vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
3086               {
3087                 acl_print_acl (vm, am, *pj);
3088               }
3089               vlib_cli_output (vm, "\n");
3090             }
3091         }
3092       if (detail && (swi < vec_len (am->input_lc_index_by_sw_if_index)))
3093         {
3094           vlib_cli_output (vm, "   input lookup context index: %d",
3095                            am->input_lc_index_by_sw_if_index[swi]);
3096         }
3097       if (detail && (swi < vec_len (am->output_lc_index_by_sw_if_index)))
3098         {
3099           vlib_cli_output (vm, "  output lookup context index: %d",
3100                            am->output_lc_index_by_sw_if_index[swi]);
3101         }
3102     }
3103
3104 }
3105
3106
3107 static clib_error_t *
3108 acl_show_aclplugin_decode_5tuple_fn (vlib_main_t * vm,
3109                                      unformat_input_t * input,
3110                                      vlib_cli_command_t * cmd)
3111 {
3112   clib_error_t *error = 0;
3113   u64 five_tuple[6] = { 0, 0, 0, 0, 0, 0 };
3114
3115   if (unformat
3116       (input, "%llx %llx %llx %llx %llx %llx", &five_tuple[0], &five_tuple[1],
3117        &five_tuple[2], &five_tuple[3], &five_tuple[4], &five_tuple[5]))
3118     vlib_cli_output (vm, "5-tuple structure decode: %U\n\n",
3119                      format_acl_plugin_5tuple, five_tuple);
3120   else
3121     error = clib_error_return (0, "expecting 6 hex integers");
3122   return error;
3123 }
3124
3125
3126 static clib_error_t *
3127 acl_show_aclplugin_interface_fn (vlib_main_t * vm,
3128                                  unformat_input_t *
3129                                  input, vlib_cli_command_t * cmd)
3130 {
3131   clib_error_t *error = 0;
3132   acl_main_t *am = &acl_main;
3133
3134   u32 sw_if_index = ~0;
3135   (void) unformat (input, "sw_if_index %u", &sw_if_index);
3136   int show_acl = unformat (input, "acl");
3137   int detail = unformat (input, "detail");
3138
3139   acl_plugin_show_interface (am, sw_if_index, show_acl, detail);
3140   return error;
3141 }
3142
3143 static clib_error_t *
3144 acl_show_aclplugin_memory_fn (vlib_main_t * vm,
3145                               unformat_input_t * input,
3146                               vlib_cli_command_t * cmd)
3147 {
3148   clib_error_t *error = 0;
3149   acl_main_t *am = &acl_main;
3150
3151   vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
3152   if (am->acl_mheap)
3153     {
3154       vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
3155     }
3156   else
3157     {
3158       vlib_cli_output (vm, " Not initialized\n");
3159     }
3160   vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
3161   if (am->hash_lookup_mheap)
3162     {
3163       vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
3164     }
3165   else
3166     {
3167       vlib_cli_output (vm, " Not initialized\n");
3168     }
3169   return error;
3170 }
3171
3172 static void
3173 acl_plugin_show_sessions (acl_main_t * am,
3174                           u32 show_session_thread_id,
3175                           u32 show_session_session_index)
3176 {
3177   vlib_main_t *vm = am->vlib_main;
3178   u16 wk;
3179   vnet_interface_main_t *im = &am->vnet_main->interface_main;
3180   vnet_sw_interface_t *swif;
3181   u64 now = clib_cpu_time_now ();
3182   u64 clocks_per_second = am->vlib_main->clib_time.clocks_per_second;
3183
3184   {
3185     u64 n_adds = am->fa_session_total_adds;
3186     u64 n_dels = am->fa_session_total_dels;
3187     u64 n_deact = am->fa_session_total_deactivations;
3188     vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
3189                      n_dels, n_adds - n_dels);
3190     vlib_cli_output (vm, "Sessions active: add %lu - deact %lu = %lu", n_adds,
3191                      n_deact, n_adds - n_deact);
3192     vlib_cli_output (vm, "Sessions being purged: deact %lu - del %lu = %lu",
3193                      n_deact, n_dels, n_deact - n_dels);
3194   }
3195   vlib_cli_output (vm, "now: %lu clocks per second: %lu", now,
3196                    clocks_per_second);
3197   vlib_cli_output (vm, "\n\nPer-thread data:");
3198   for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3199     {
3200       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3201       vlib_cli_output (vm, "Thread #%d:", wk);
3202       if (show_session_thread_id == wk
3203           && show_session_session_index < pool_len (pw->fa_sessions_pool))
3204         {
3205           vlib_cli_output (vm, "  session index %u:",
3206                            show_session_session_index);
3207           fa_session_t *sess =
3208             pw->fa_sessions_pool + show_session_session_index;
3209           u64 *m = (u64 *) & sess->info;
3210           vlib_cli_output (vm,
3211                            "    info: %016llx %016llx %016llx %016llx %016llx %016llx",
3212                            m[0], m[1], m[2], m[3], m[4], m[5]);
3213           vlib_cli_output (vm, "    sw_if_index: %u", sess->sw_if_index);
3214           vlib_cli_output (vm, "    tcp_flags_seen: %x",
3215                            sess->tcp_flags_seen.as_u16);
3216           vlib_cli_output (vm, "    last active time: %lu",
3217                            sess->last_active_time);
3218           vlib_cli_output (vm, "    thread index: %u", sess->thread_index);
3219           vlib_cli_output (vm, "    link enqueue time: %lu",
3220                            sess->link_enqueue_time);
3221           vlib_cli_output (vm, "    link next index: %u",
3222                            sess->link_next_idx);
3223           vlib_cli_output (vm, "    link prev index: %u",
3224                            sess->link_prev_idx);
3225           vlib_cli_output (vm, "    link list id: %u", sess->link_list_id);
3226         }
3227       vlib_cli_output (vm, "  connection add/del stats:", wk);
3228       pool_foreach (swif, im->sw_interfaces, (
3229                                                {
3230                                                u32 sw_if_index =
3231                                                swif->sw_if_index;
3232                                                u64 n_adds =
3233                                                sw_if_index <
3234                                                vec_len
3235                                                (pw->fa_session_adds_by_sw_if_index)
3236                                                ?
3237                                                pw->fa_session_adds_by_sw_if_index
3238                                                [sw_if_index] : 0;
3239                                                u64 n_dels =
3240                                                sw_if_index <
3241                                                vec_len
3242                                                (pw->fa_session_dels_by_sw_if_index)
3243                                                ?
3244                                                pw->fa_session_dels_by_sw_if_index
3245                                                [sw_if_index] : 0;
3246                                                u64 n_epoch_changes =
3247                                                sw_if_index <
3248                                                vec_len
3249                                                (pw->fa_session_epoch_change_by_sw_if_index)
3250                                                ?
3251                                                pw->fa_session_epoch_change_by_sw_if_index
3252                                                [sw_if_index] : 0;
3253                                                vlib_cli_output (vm,
3254                                                                 "    sw_if_index %d: add %lu - del %lu = %lu; epoch chg: %lu",
3255                                                                 sw_if_index,
3256                                                                 n_adds,
3257                                                                 n_dels,
3258                                                                 n_adds -
3259                                                                 n_dels,
3260                                                                 n_epoch_changes);
3261                                                }
3262                     ));
3263
3264       vlib_cli_output (vm, "  connection timeout type lists:", wk);
3265       u8 tt = 0;
3266       for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
3267         {
3268           u32 head_session_index = pw->fa_conn_list_head[tt];
3269           vlib_cli_output (vm, "  fa_conn_list_head[%d]: %d", tt,
3270                            head_session_index);
3271           if (~0 != head_session_index)
3272             {
3273               fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
3274               vlib_cli_output (vm, "    last active time: %lu",
3275                                sess->last_active_time);
3276               vlib_cli_output (vm, "    link enqueue time: %lu",
3277                                sess->link_enqueue_time);
3278             }
3279         }
3280
3281       vlib_cli_output (vm, "  Next expiry time: %lu", pw->next_expiry_time);
3282       vlib_cli_output (vm, "  Requeue until time: %lu",
3283                        pw->requeue_until_time);
3284       vlib_cli_output (vm, "  Current time wait interval: %lu",
3285                        pw->current_time_wait_interval);
3286       vlib_cli_output (vm, "  Count of deleted sessions: %lu",
3287                        pw->cnt_deleted_sessions);
3288       vlib_cli_output (vm, "  Delete already deleted: %lu",
3289                        pw->cnt_already_deleted_sessions);
3290       vlib_cli_output (vm, "  Session timers restarted: %lu",
3291                        pw->cnt_session_timer_restarted);
3292       vlib_cli_output (vm, "  Swipe until this time: %lu",
3293                        pw->swipe_end_time);
3294       vlib_cli_output (vm, "  sw_if_index serviced bitmap: %U",
3295                        format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
3296       vlib_cli_output (vm, "  pending clear intfc bitmap : %U",
3297                        format_bitmap_hex,
3298                        pw->pending_clear_sw_if_index_bitmap);
3299       vlib_cli_output (vm, "  clear in progress: %u", pw->clear_in_process);
3300       vlib_cli_output (vm, "  interrupt is pending: %d",
3301                        pw->interrupt_is_pending);
3302       vlib_cli_output (vm, "  interrupt is needed: %d",
3303                        pw->interrupt_is_needed);
3304       vlib_cli_output (vm, "  interrupt is unwanted: %d",
3305                        pw->interrupt_is_unwanted);
3306       vlib_cli_output (vm, "  interrupt generation: %d",
3307                        pw->interrupt_generation);
3308       vlib_cli_output (vm, "  received session change requests: %d",
3309                        pw->rcvd_session_change_requests);
3310       vlib_cli_output (vm, "  sent session change requests: %d",
3311                        pw->sent_session_change_requests);
3312     }
3313   vlib_cli_output (vm, "\n\nConn cleaner thread counters:");
3314 #define _(cnt, desc) vlib_cli_output(vm, "             %20lu: %s", am->cnt, desc);
3315   foreach_fa_cleaner_counter;
3316 #undef _
3317   vlib_cli_output (vm, "Interrupt generation: %d",
3318                    am->fa_interrupt_generation);
3319   vlib_cli_output (vm,
3320                    "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
3321                    am->fa_min_deleted_sessions_per_interval,
3322                    am->fa_max_deleted_sessions_per_interval,
3323                    am->fa_cleaner_wait_time_increment * 1000.0,
3324                    ((f64) am->fa_current_cleaner_timer_wait_interval) *
3325                    1000.0 / (f64) vm->clib_time.clocks_per_second);
3326   vlib_cli_output (vm, "Reclassify sessions: %d", am->reclassify_sessions);
3327 }
3328
3329 static clib_error_t *
3330 acl_show_aclplugin_sessions_fn (vlib_main_t * vm,
3331                                 unformat_input_t * input,
3332                                 vlib_cli_command_t * cmd)
3333 {
3334   clib_error_t *error = 0;
3335   acl_main_t *am = &acl_main;
3336
3337   u32 show_bihash_verbose = 0;
3338   u32 show_session_thread_id = ~0;
3339   u32 show_session_session_index = ~0;
3340   (void) unformat (input, "thread %u index %u", &show_session_thread_id,
3341                    &show_session_session_index);
3342   (void) unformat (input, "verbose %u", &show_bihash_verbose);
3343
3344   acl_plugin_show_sessions (am, show_session_thread_id,
3345                             show_session_session_index);
3346   show_fa_sessions_hash (vm, show_bihash_verbose);
3347   return error;
3348 }
3349
3350 static clib_error_t *
3351 acl_show_aclplugin_tables_fn (vlib_main_t * vm,
3352                               unformat_input_t * input,
3353                               vlib_cli_command_t * cmd)
3354 {
3355   clib_error_t *error = 0;
3356
3357   u32 acl_index = ~0;
3358   u32 lc_index = ~0;
3359   int show_acl_hash_info = 0;
3360   int show_applied_info = 0;
3361   int show_mask_type = 0;
3362   int show_bihash = 0;
3363   u32 show_bihash_verbose = 0;
3364
3365   if (unformat (input, "acl"))
3366     {
3367       show_acl_hash_info = 1;
3368       /* mask-type is handy to see as well right there */
3369       show_mask_type = 1;
3370       unformat (input, "index %u", &acl_index);
3371     }
3372   else if (unformat (input, "applied"))
3373     {
3374       show_applied_info = 1;
3375       unformat (input, "lc_index %u", &lc_index);
3376     }
3377   else if (unformat (input, "mask"))
3378     {
3379       show_mask_type = 1;
3380     }
3381   else if (unformat (input, "hash"))
3382     {
3383       show_bihash = 1;
3384       unformat (input, "verbose %u", &show_bihash_verbose);
3385     }
3386
3387   if (!
3388       (show_mask_type || show_acl_hash_info || show_applied_info
3389        || show_bihash))
3390     {
3391       /* if no qualifiers specified, show all */
3392       show_mask_type = 1;
3393       show_acl_hash_info = 1;
3394       show_applied_info = 1;
3395       show_bihash = 1;
3396     }
3397   if (show_mask_type)
3398     acl_plugin_show_tables_mask_type ();
3399   if (show_acl_hash_info)
3400     acl_plugin_show_tables_acl_hash_info (acl_index);
3401   if (show_applied_info)
3402     acl_plugin_show_tables_applied_info (lc_index);
3403   if (show_bihash)
3404     acl_plugin_show_tables_bihash (show_bihash_verbose);
3405
3406   return error;
3407 }
3408
3409 static clib_error_t *
3410 acl_clear_aclplugin_fn (vlib_main_t * vm,
3411                         unformat_input_t * input, vlib_cli_command_t * cmd)
3412 {
3413   clib_error_t *error = 0;
3414   acl_main_t *am = &acl_main;
3415   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
3416                              ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
3417   return error;
3418 }
3419
3420  /* *INDENT-OFF* */
3421 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
3422     .path = "set acl-plugin",
3423     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
3424     .function = acl_set_aclplugin_fn,
3425 };
3426
3427 VLIB_CLI_COMMAND (aclplugin_show_acl_command, static) = {
3428     .path = "show acl-plugin acl",
3429     .short_help = "show acl-plugin acl [index N]",
3430     .function = acl_show_aclplugin_acl_fn,
3431 };
3432
3433 VLIB_CLI_COMMAND (aclplugin_show_lookup_context_command, static) = {
3434     .path = "show acl-plugin lookup context",
3435     .short_help = "show acl-plugin lookup context [index N]",
3436     .function = acl_show_aclplugin_lookup_context_fn,
3437 };
3438
3439 VLIB_CLI_COMMAND (aclplugin_show_lookup_user_command, static) = {
3440     .path = "show acl-plugin lookup user",
3441     .short_help = "show acl-plugin lookup user [index N]",
3442     .function = acl_show_aclplugin_lookup_user_fn,
3443 };
3444
3445 VLIB_CLI_COMMAND (aclplugin_show_decode_5tuple_command, static) = {
3446     .path = "show acl-plugin decode 5tuple",
3447     .short_help = "show acl-plugin decode 5tuple XXXX XXXX XXXX XXXX XXXX XXXX",
3448     .function = acl_show_aclplugin_decode_5tuple_fn,
3449 };
3450
3451 VLIB_CLI_COMMAND (aclplugin_show_interface_command, static) = {
3452     .path = "show acl-plugin interface",
3453     .short_help = "show acl-plugin interface [sw_if_index N] [acl]",
3454     .function = acl_show_aclplugin_interface_fn,
3455 };
3456
3457 VLIB_CLI_COMMAND (aclplugin_show_memory_command, static) = {
3458     .path = "show acl-plugin memory",
3459     .short_help = "show acl-plugin memory",
3460     .function = acl_show_aclplugin_memory_fn,
3461 };
3462
3463 VLIB_CLI_COMMAND (aclplugin_show_sessions_command, static) = {
3464     .path = "show acl-plugin sessions",
3465     .short_help = "show acl-plugin sessions",
3466     .function = acl_show_aclplugin_sessions_fn,
3467 };
3468
3469 VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
3470     .path = "show acl-plugin tables",
3471     .short_help = "show acl-plugin tables [ acl [index N] | applied [ lc_index N ] | mask | hash [verbose N] ]",
3472     .function = acl_show_aclplugin_tables_fn,
3473 };
3474
3475 VLIB_CLI_COMMAND (aclplugin_show_macip_acl_command, static) = {
3476     .path = "show acl-plugin macip acl",
3477     .short_help = "show acl-plugin macip acl [index N]",
3478     .function = acl_show_aclplugin_macip_acl_fn,
3479 };
3480
3481 VLIB_CLI_COMMAND (aclplugin_show_macip_interface_command, static) = {
3482     .path = "show acl-plugin macip interface",
3483     .short_help = "show acl-plugin macip interface",
3484     .function = acl_show_aclplugin_macip_interface_fn,
3485 };
3486
3487 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
3488     .path = "clear acl-plugin sessions",
3489     .short_help = "clear acl-plugin sessions",
3490     .function = acl_clear_aclplugin_fn,
3491 };
3492 /* *INDENT-ON* */
3493
3494 static clib_error_t *
3495 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
3496 {
3497   acl_main_t *am = &acl_main;
3498   u32 conn_table_hash_buckets;
3499   uword conn_table_hash_memory_size;
3500   u32 conn_table_max_entries;
3501   uword main_heap_size;
3502   uword hash_heap_size;
3503   u32 hash_lookup_hash_buckets;
3504   uword hash_lookup_hash_memory;
3505   u32 reclassify_sessions;
3506   u32 use_tuple_merge;
3507   u32 tuple_merge_split_threshold;
3508
3509   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3510     {
3511       if (unformat
3512           (input, "connection hash buckets %d", &conn_table_hash_buckets))
3513         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
3514       else
3515         if (unformat
3516             (input, "connection hash memory %U", unformat_memory_size,
3517              &conn_table_hash_memory_size))
3518         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
3519       else if (unformat (input, "connection count max %d",
3520                          &conn_table_max_entries))
3521         am->fa_conn_table_max_entries = conn_table_max_entries;
3522       else
3523         if (unformat
3524             (input, "main heap size %U", unformat_memory_size,
3525              &main_heap_size))
3526         am->acl_mheap_size = main_heap_size;
3527       else
3528         if (unformat
3529             (input, "hash lookup heap size %U", unformat_memory_size,
3530              &hash_heap_size))
3531         am->hash_lookup_mheap_size = hash_heap_size;
3532       else if (unformat (input, "hash lookup hash buckets %d",
3533                          &hash_lookup_hash_buckets))
3534         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
3535       else
3536         if (unformat
3537             (input, "hash lookup hash memory %U", unformat_memory_size,
3538              &hash_lookup_hash_memory))
3539         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
3540       else if (unformat (input, "use tuple merge %d", &use_tuple_merge))
3541         am->use_tuple_merge = use_tuple_merge;
3542       else
3543         if (unformat
3544             (input, "tuple merge split threshold %d",
3545              &tuple_merge_split_threshold))
3546         am->tuple_merge_split_threshold = tuple_merge_split_threshold;
3547
3548       else if (unformat (input, "reclassify sessions %d",
3549                          &reclassify_sessions))
3550         am->reclassify_sessions = reclassify_sessions;
3551
3552       else
3553         return clib_error_return (0, "unknown input '%U'",
3554                                   format_unformat_error, input);
3555     }
3556   return 0;
3557 }
3558
3559 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
3560
3561 static clib_error_t *
3562 acl_init (vlib_main_t * vm)
3563 {
3564   acl_main_t *am = &acl_main;
3565   clib_error_t *error = 0;
3566   clib_memset (am, 0, sizeof (*am));
3567   am->vlib_main = vm;
3568   am->vnet_main = vnet_get_main ();
3569   am->log_default = vlib_log_register_class ("acl_plugin", 0);
3570
3571   u8 *name = format (0, "acl_%08x%c", api_version, 0);
3572
3573   /* Ask for a correctly-sized block of API message decode slots */
3574   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
3575                                             VL_MSG_FIRST_AVAILABLE);
3576
3577   error = acl_plugin_api_hookup (vm);
3578
3579   /* Add our API messages to the global name_crc hash table */
3580   setup_message_id_table (am, &api_main);
3581
3582   vec_free (name);
3583
3584   if (error)
3585     return error;
3586
3587   error = acl_plugin_exports_init (&acl_plugin);
3588
3589   if (error)
3590     return error;
3591
3592   am->acl_mheap_size = 0;       /* auto size when initializing */
3593   am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
3594
3595   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
3596   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
3597
3598   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
3599     TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
3600   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
3601     TCP_SESSION_IDLE_TIMEOUT_SEC;
3602   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
3603     UDP_SESSION_IDLE_TIMEOUT_SEC;
3604
3605   am->fa_conn_table_hash_num_buckets =
3606     ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
3607   am->fa_conn_table_hash_memory_size =
3608     ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
3609   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
3610   am->reclassify_sessions = 0;
3611   vlib_thread_main_t *tm = vlib_get_thread_main ();
3612
3613   am->fa_min_deleted_sessions_per_interval =
3614     ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
3615   am->fa_max_deleted_sessions_per_interval =
3616     ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
3617   am->fa_cleaner_wait_time_increment =
3618     ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
3619
3620   vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
3621   {
3622     u16 wk;
3623     for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3624       {
3625         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3626         if (tm->n_vlib_mains > 1)
3627           {
3628             clib_spinlock_init (&pw->pending_session_change_request_lock);
3629           }
3630         vec_validate (pw->expired,
3631                       ACL_N_TIMEOUTS *
3632                       am->fa_max_deleted_sessions_per_interval);
3633         _vec_len (pw->expired) = 0;
3634         vec_validate_init_empty (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1,
3635                                  FA_SESSION_BOGUS_INDEX);
3636         vec_validate_init_empty (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1,
3637                                  FA_SESSION_BOGUS_INDEX);
3638         vec_validate_init_empty (pw->fa_conn_list_head_expiry_time,
3639                                  ACL_N_TIMEOUTS - 1, ~0ULL);
3640       }
3641   }
3642
3643   am->fa_cleaner_cnt_delete_by_sw_index = 0;
3644   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
3645   am->fa_cleaner_cnt_unknown_event = 0;
3646   am->fa_cleaner_cnt_timer_restarted = 0;
3647   am->fa_cleaner_cnt_wait_with_timeout = 0;
3648
3649
3650 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
3651   foreach_acl_eh
3652 #undef _
3653     am->l4_match_nonfirst_fragment = 1;
3654
3655   /* use the new fancy hash-based matching */
3656   am->use_hash_acl_matching = 1;
3657   /* use tuplemerge by default */
3658   am->use_tuple_merge = 1;
3659   /* Set the default threshold */
3660   am->tuple_merge_split_threshold = TM_SPLIT_THRESHOLD;
3661
3662   am->interface_acl_user_id = ~0;       /* defer till the first use */
3663
3664   return error;
3665 }
3666
3667 VLIB_INIT_FUNCTION (acl_init);
3668
3669
3670 /*
3671  * fd.io coding-style-patch-verification: ON
3672  *
3673  * Local Variables:
3674  * eval: (c-set-style "gnu")
3675  * End:
3676  */