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