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