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