acl-plugin: implement ACL lookup contexts for "ACL as a service" use by other plugins
[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
2169   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
2170   /* No point in deleting MACIP ACL which is not applied */
2171   if (~0 == macip_acl_index)
2172     return VNET_API_ERROR_NO_SUCH_ENTRY;
2173
2174   void *oldheap = acl_set_heap (am);
2175   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
2176   vec_validate_init_empty (am->sw_if_index_vec_by_macip_acl, macip_acl_index,
2177                            ~0);
2178   clib_mem_set_heap (oldheap);
2179   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
2180   /* remove the classifier tables off the interface L2 ACL */
2181   rv =
2182     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
2183                               a->ip6_table_index, a->l2_table_index, 0);
2184   rv |=
2185     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
2186                                a->out_ip4_table_index, a->out_ip6_table_index,
2187                                a->out_l2_table_index, 0);
2188   /* Unset the MACIP ACL index */
2189   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
2190   am->sw_if_index_vec_by_macip_acl[macip_acl_index] = ~0;
2191   return rv;
2192 }
2193
2194 /* No check for validity of sw_if_index - the callers were supposed to validate */
2195
2196 static int
2197 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
2198                              u32 macip_acl_index)
2199 {
2200   macip_acl_list_t *a;
2201   int rv;
2202   if (pool_is_free_index (am->macip_acls, macip_acl_index))
2203     {
2204       return VNET_API_ERROR_NO_SUCH_ENTRY;
2205     }
2206   void *oldheap = acl_set_heap (am);
2207   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
2208   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
2209   vec_validate_init_empty (am->sw_if_index_vec_by_macip_acl, macip_acl_index,
2210                            ~0);
2211   clib_mem_set_heap (oldheap);
2212   /* If there already a MACIP ACL applied, unapply it */
2213   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2214     macip_acl_interface_del_acl (am, sw_if_index);
2215   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
2216   am->sw_if_index_vec_by_macip_acl[macip_acl_index] = sw_if_index;
2217
2218   /* Apply the classifier tables for L2 ACLs */
2219   rv =
2220     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
2221                               a->ip6_table_index, a->l2_table_index, 1);
2222   rv |=
2223     vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
2224                                a->out_ip4_table_index, a->out_ip6_table_index,
2225                                a->out_l2_table_index, 1);
2226   return rv;
2227 }
2228
2229 static int
2230 macip_acl_del_list (u32 acl_list_index)
2231 {
2232   acl_main_t *am = &acl_main;
2233   macip_acl_list_t *a;
2234   int i;
2235   if (pool_is_free_index (am->macip_acls, acl_list_index))
2236     {
2237       return VNET_API_ERROR_NO_SUCH_ENTRY;
2238     }
2239
2240   /* delete any references to the ACL */
2241   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
2242     {
2243       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
2244         {
2245           macip_acl_interface_del_acl (am, i);
2246         }
2247     }
2248
2249   void *oldheap = acl_set_heap (am);
2250   /* Now that classifier tables are detached, clean them up */
2251   macip_destroy_classify_tables (am, acl_list_index);
2252
2253   /* now we can delete the ACL itself */
2254   a = pool_elt_at_index (am->macip_acls, acl_list_index);
2255   if (a->rules)
2256     {
2257       vec_free (a->rules);
2258     }
2259   pool_put (am->macip_acls, a);
2260   clib_mem_set_heap (oldheap);
2261   return 0;
2262 }
2263
2264
2265 static int
2266 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
2267                                  u32 acl_list_index)
2268 {
2269   acl_main_t *am = &acl_main;
2270   int rv = -1;
2271   if (is_add)
2272     {
2273       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
2274     }
2275   else
2276     {
2277       rv = macip_acl_interface_del_acl (am, sw_if_index);
2278     }
2279   return rv;
2280 }
2281
2282 /*
2283  * If the client does not allocate enough memory for a variable-length
2284  * message, and then proceed to use it as if the full memory allocated,
2285  * absent the check we happily consume that on the VPP side, and go
2286  * along as if nothing happened. However, the resulting
2287  * effects range from just garbage in the API decode
2288  * (because the decoder snoops too far), to potential memory
2289  * corruptions.
2290  *
2291  * This verifies that the actual length of the message is
2292  * at least expected_len, and complains loudly if it is not.
2293  *
2294  * A failing check here is 100% a software bug on the API user side,
2295  * so we might as well yell.
2296  *
2297  */
2298 static int
2299 verify_message_len (void *mp, u32 expected_len, char *where)
2300 {
2301   u32 supplied_len = vl_msg_api_get_msg_length (mp);
2302   if (supplied_len < expected_len)
2303     {
2304       clib_warning ("%s: Supplied message length %d is less than expected %d",
2305                     where, supplied_len, expected_len);
2306       return 0;
2307     }
2308   else
2309     {
2310       return 1;
2311     }
2312 }
2313
2314 /* API message handler */
2315 static void
2316 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
2317 {
2318   vl_api_acl_add_replace_reply_t *rmp;
2319   acl_main_t *am = &acl_main;
2320   int rv;
2321   u32 acl_list_index = ntohl (mp->acl_index);
2322   u32 acl_count = ntohl (mp->count);
2323   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2324
2325   if (verify_message_len (mp, expected_len, "acl_add_replace"))
2326     {
2327       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2328     }
2329   else
2330     {
2331       rv = VNET_API_ERROR_INVALID_VALUE;
2332     }
2333
2334   /* *INDENT-OFF* */
2335   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
2336   ({
2337     rmp->acl_index = htonl(acl_list_index);
2338   }));
2339   /* *INDENT-ON* */
2340 }
2341
2342 static void
2343 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
2344 {
2345   acl_main_t *am = &acl_main;
2346   vl_api_acl_del_reply_t *rmp;
2347   int rv;
2348
2349   rv = acl_del_list (ntohl (mp->acl_index));
2350
2351   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
2352 }
2353
2354 static void
2355 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
2356 {
2357   acl_main_t *am = &acl_main;
2358   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2359   u32 sw_if_index = ntohl (mp->sw_if_index);
2360   vl_api_acl_interface_add_del_reply_t *rmp;
2361   int rv = -1;
2362
2363   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2364     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2365   else
2366     rv =
2367       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
2368                                        mp->is_input, ntohl (mp->acl_index));
2369
2370   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
2371 }
2372
2373 static void
2374   vl_api_acl_interface_set_acl_list_t_handler
2375   (vl_api_acl_interface_set_acl_list_t * mp)
2376 {
2377   acl_main_t *am = &acl_main;
2378   vl_api_acl_interface_set_acl_list_reply_t *rmp;
2379   int rv = 0;
2380   int i;
2381   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2382   u32 sw_if_index = ntohl (mp->sw_if_index);
2383
2384   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2385     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2386   else
2387     {
2388       int may_clear_sessions = 1;
2389       for (i = 0; i < mp->count; i++)
2390         {
2391           if (acl_is_not_defined (am, ntohl (mp->acls[i])))
2392             {
2393               /* ACL does not exist, so we can not apply it */
2394               rv = VNET_API_ERROR_NO_SUCH_ENTRY;
2395             }
2396         }
2397       if (0 == rv)
2398         {
2399           void *oldheap = acl_set_heap (am);
2400
2401           u32 *in_acl_vec = 0;
2402           u32 *out_acl_vec = 0;
2403           for (i = 0; i < mp->count; i++)
2404             if (i < mp->n_input)
2405               vec_add1 (in_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
2406             else
2407               vec_add1 (out_acl_vec, clib_net_to_host_u32 (mp->acls[i]));
2408
2409           rv =
2410             acl_interface_set_inout_acl_list (am, sw_if_index, 0, out_acl_vec,
2411                                               &may_clear_sessions);
2412           rv = rv
2413             || acl_interface_set_inout_acl_list (am, sw_if_index, 1,
2414                                                  in_acl_vec,
2415                                                  &may_clear_sessions);
2416           vec_free (in_acl_vec);
2417           vec_free (out_acl_vec);
2418           clib_mem_set_heap (oldheap);
2419         }
2420     }
2421
2422   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
2423 }
2424
2425 static void
2426 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
2427 {
2428   api_rule->is_permit = r->is_permit;
2429   api_rule->is_ipv6 = r->is_ipv6;
2430   if (r->is_ipv6)
2431     {
2432       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
2433       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
2434     }
2435   else
2436     {
2437       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
2438       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
2439     }
2440   api_rule->src_ip_prefix_len = r->src_prefixlen;
2441   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
2442   api_rule->proto = r->proto;
2443   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
2444   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
2445   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
2446   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
2447   api_rule->tcp_flags_mask = r->tcp_flags_mask;
2448   api_rule->tcp_flags_value = r->tcp_flags_value;
2449 }
2450
2451 static void
2452 send_acl_details (acl_main_t * am, vl_api_registration_t * reg,
2453                   acl_list_t * acl, u32 context)
2454 {
2455   vl_api_acl_details_t *mp;
2456   vl_api_acl_rule_t *rules;
2457   int i;
2458   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
2459   void *oldheap = acl_set_heap (am);
2460
2461   mp = vl_msg_api_alloc (msg_size);
2462   memset (mp, 0, msg_size);
2463   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
2464
2465   /* fill in the message */
2466   mp->context = context;
2467   mp->count = htonl (acl->count);
2468   mp->acl_index = htonl (acl - am->acls);
2469   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2470   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
2471   rules = mp->r;
2472   for (i = 0; i < acl->count; i++)
2473     {
2474       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
2475     }
2476
2477   clib_mem_set_heap (oldheap);
2478   vl_api_send_msg (reg, (u8 *) mp);
2479 }
2480
2481
2482 static void
2483 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
2484 {
2485   acl_main_t *am = &acl_main;
2486   u32 acl_index;
2487   acl_list_t *acl;
2488   int rv = -1;
2489   vl_api_registration_t *reg;
2490
2491   reg = vl_api_client_index_to_registration (mp->client_index);
2492   if (!reg)
2493     return;
2494
2495   if (mp->acl_index == ~0)
2496     {
2497     /* *INDENT-OFF* */
2498     /* Just dump all ACLs */
2499     pool_foreach (acl, am->acls,
2500     ({
2501       send_acl_details(am, reg, acl, mp->context);
2502     }));
2503     /* *INDENT-ON* */
2504     }
2505   else
2506     {
2507       acl_index = ntohl (mp->acl_index);
2508       if (!pool_is_free_index (am->acls, acl_index))
2509         {
2510           acl = pool_elt_at_index (am->acls, acl_index);
2511           send_acl_details (am, reg, acl, mp->context);
2512         }
2513     }
2514
2515   if (rv == -1)
2516     {
2517       /* FIXME API: should we signal an error here at all ? */
2518       return;
2519     }
2520 }
2521
2522 static void
2523 send_acl_interface_list_details (acl_main_t * am,
2524                                  vl_api_registration_t * reg,
2525                                  u32 sw_if_index, u32 context)
2526 {
2527   vl_api_acl_interface_list_details_t *mp;
2528   int msg_size;
2529   int n_input;
2530   int n_output;
2531   int count;
2532   int i = 0;
2533   void *oldheap = acl_set_heap (am);
2534
2535   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
2536   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
2537
2538   clib_mem_set_heap (oldheap);
2539
2540   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
2541   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
2542   count = n_input + n_output;
2543
2544   msg_size = sizeof (*mp);
2545   msg_size += sizeof (mp->acls[0]) * count;
2546
2547   mp = vl_msg_api_alloc (msg_size);
2548   memset (mp, 0, msg_size);
2549   mp->_vl_msg_id =
2550     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2551
2552   /* fill in the message */
2553   mp->context = context;
2554   mp->sw_if_index = htonl (sw_if_index);
2555   mp->count = count;
2556   mp->n_input = n_input;
2557   for (i = 0; i < n_input; i++)
2558     {
2559       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
2560     }
2561   for (i = 0; i < n_output; i++)
2562     {
2563       mp->acls[n_input + i] =
2564         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
2565     }
2566   vl_api_send_msg (reg, (u8 *) mp);
2567 }
2568
2569 static void
2570 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
2571                                           mp)
2572 {
2573   acl_main_t *am = &acl_main;
2574   vnet_sw_interface_t *swif;
2575   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2576
2577   u32 sw_if_index;
2578   vl_api_registration_t *reg;
2579
2580   reg = vl_api_client_index_to_registration (mp->client_index);
2581   if (!reg)
2582     return;
2583
2584   if (mp->sw_if_index == ~0)
2585     {
2586     /* *INDENT-OFF* */
2587     pool_foreach (swif, im->sw_interfaces,
2588     ({
2589       send_acl_interface_list_details(am, reg, swif->sw_if_index, mp->context);
2590     }));
2591     /* *INDENT-ON* */
2592     }
2593   else
2594     {
2595       sw_if_index = ntohl (mp->sw_if_index);
2596       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2597         send_acl_interface_list_details (am, reg, sw_if_index, mp->context);
2598     }
2599 }
2600
2601 /* MACIP ACL API handlers */
2602
2603 static void
2604 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
2605 {
2606   vl_api_macip_acl_add_reply_t *rmp;
2607   acl_main_t *am = &acl_main;
2608   int rv;
2609   u32 acl_list_index = ~0;
2610   u32 acl_count = ntohl (mp->count);
2611   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2612
2613   if (verify_message_len (mp, expected_len, "macip_acl_add"))
2614     {
2615       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2616     }
2617   else
2618     {
2619       rv = VNET_API_ERROR_INVALID_VALUE;
2620     }
2621
2622   /* *INDENT-OFF* */
2623   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
2624   ({
2625     rmp->acl_index = htonl(acl_list_index);
2626   }));
2627   /* *INDENT-ON* */
2628 }
2629
2630 static void
2631 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
2632 {
2633   vl_api_macip_acl_add_replace_reply_t *rmp;
2634   acl_main_t *am = &acl_main;
2635   int rv;
2636   u32 acl_list_index = ntohl (mp->acl_index);
2637   u32 acl_count = ntohl (mp->count);
2638   u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2639
2640   if (verify_message_len (mp, expected_len, "macip_acl_add_replace"))
2641     {
2642       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2643     }
2644   else
2645     {
2646       rv = VNET_API_ERROR_INVALID_VALUE;
2647     }
2648
2649   /* *INDENT-OFF* */
2650   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
2651   ({
2652     rmp->acl_index = htonl(acl_list_index);
2653   }));
2654   /* *INDENT-ON* */
2655 }
2656
2657 static void
2658 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
2659 {
2660   acl_main_t *am = &acl_main;
2661   vl_api_macip_acl_del_reply_t *rmp;
2662   int rv;
2663
2664   rv = macip_acl_del_list (ntohl (mp->acl_index));
2665
2666   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
2667 }
2668
2669 static void
2670   vl_api_macip_acl_interface_add_del_t_handler
2671   (vl_api_macip_acl_interface_add_del_t * mp)
2672 {
2673   acl_main_t *am = &acl_main;
2674   vl_api_macip_acl_interface_add_del_reply_t *rmp;
2675   int rv = -1;
2676   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2677   u32 sw_if_index = ntohl (mp->sw_if_index);
2678
2679   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2680     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2681   else
2682     rv =
2683       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
2684                                        ntohl (mp->acl_index));
2685
2686   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
2687 }
2688
2689 static void
2690 send_macip_acl_details (acl_main_t * am, vl_api_registration_t * reg,
2691                         macip_acl_list_t * acl, u32 context)
2692 {
2693   vl_api_macip_acl_details_t *mp;
2694   vl_api_macip_acl_rule_t *rules;
2695   macip_acl_rule_t *r;
2696   int i;
2697   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
2698
2699   mp = vl_msg_api_alloc (msg_size);
2700   memset (mp, 0, msg_size);
2701   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
2702
2703   /* fill in the message */
2704   mp->context = context;
2705   if (acl)
2706     {
2707       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2708       mp->count = htonl (acl->count);
2709       mp->acl_index = htonl (acl - am->macip_acls);
2710       rules = mp->r;
2711       for (i = 0; i < acl->count; i++)
2712         {
2713           r = &acl->rules[i];
2714           rules[i].is_permit = r->is_permit;
2715           rules[i].is_ipv6 = r->is_ipv6;
2716           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
2717           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
2718                   sizeof (r->src_mac_mask));
2719           if (r->is_ipv6)
2720             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
2721                     sizeof (r->src_ip_addr.ip6));
2722           else
2723             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
2724                     sizeof (r->src_ip_addr.ip4));
2725           rules[i].src_ip_prefix_len = r->src_prefixlen;
2726         }
2727     }
2728   else
2729     {
2730       /* No martini, no party - no ACL applied to this interface. */
2731       mp->acl_index = ~0;
2732       mp->count = 0;
2733     }
2734
2735   vl_api_send_msg (reg, (u8 *) mp);
2736 }
2737
2738
2739 static void
2740 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
2741 {
2742   acl_main_t *am = &acl_main;
2743   macip_acl_list_t *acl;
2744
2745   vl_api_registration_t *reg;
2746
2747   reg = vl_api_client_index_to_registration (mp->client_index);
2748   if (!reg)
2749     return;
2750
2751   if (mp->acl_index == ~0)
2752     {
2753       /* Just dump all ACLs for now, with sw_if_index = ~0 */
2754       pool_foreach (acl, am->macip_acls, (
2755                                            {
2756                                            send_macip_acl_details (am, reg,
2757                                                                    acl,
2758                                                                    mp->context);
2759                                            }
2760                     ));
2761       /* *INDENT-ON* */
2762     }
2763   else
2764     {
2765       u32 acl_index = ntohl (mp->acl_index);
2766       if (!pool_is_free_index (am->macip_acls, acl_index))
2767         {
2768           acl = pool_elt_at_index (am->macip_acls, acl_index);
2769           send_macip_acl_details (am, reg, acl, mp->context);
2770         }
2771     }
2772 }
2773
2774 static void
2775 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
2776                                           mp)
2777 {
2778   acl_main_t *am = &acl_main;
2779   vl_api_macip_acl_interface_get_reply_t *rmp;
2780   u32 count = vec_len (am->macip_acl_by_sw_if_index);
2781   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
2782   vl_api_registration_t *reg;
2783   int i;
2784
2785   reg = vl_api_client_index_to_registration (mp->client_index);
2786   if (!reg)
2787     return;
2788
2789   rmp = vl_msg_api_alloc (msg_size);
2790   memset (rmp, 0, msg_size);
2791   rmp->_vl_msg_id =
2792     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
2793   rmp->context = mp->context;
2794   rmp->count = htonl (count);
2795   for (i = 0; i < count; i++)
2796     {
2797       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
2798     }
2799
2800   vl_api_send_msg (reg, (u8 *) rmp);
2801 }
2802
2803 static void
2804 send_macip_acl_interface_list_details (acl_main_t * am,
2805                                        vl_api_registration_t * reg,
2806                                        u32 sw_if_index,
2807                                        u32 acl_index, u32 context)
2808 {
2809   vl_api_macip_acl_interface_list_details_t *rmp;
2810   /* at this time there is only ever 1 mac ip acl per interface */
2811   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
2812
2813   rmp = vl_msg_api_alloc (msg_size);
2814   memset (rmp, 0, msg_size);
2815   rmp->_vl_msg_id =
2816     ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2817
2818   /* fill in the message */
2819   rmp->context = context;
2820   rmp->count = 1;
2821   rmp->sw_if_index = htonl (sw_if_index);
2822   rmp->acls[0] = htonl (acl_index);
2823
2824   vl_api_send_msg (reg, (u8 *) rmp);
2825 }
2826
2827 static void
2828   vl_api_macip_acl_interface_list_dump_t_handler
2829   (vl_api_macip_acl_interface_list_dump_t * mp)
2830 {
2831   vl_api_registration_t *reg;
2832   acl_main_t *am = &acl_main;
2833   u32 sw_if_index = ntohl (mp->sw_if_index);
2834
2835   reg = vl_api_client_index_to_registration (mp->client_index);
2836   if (!reg)
2837     return;
2838
2839   if (sw_if_index == ~0)
2840     {
2841       vec_foreach_index (sw_if_index, am->macip_acl_by_sw_if_index)
2842       {
2843         if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2844           {
2845             send_macip_acl_interface_list_details (am, reg, sw_if_index,
2846                                                    am->macip_acl_by_sw_if_index
2847                                                    [sw_if_index],
2848                                                    mp->context);
2849           }
2850       }
2851     }
2852   else
2853     {
2854       if (vec_len (am->macip_acl_by_sw_if_index) > sw_if_index)
2855         {
2856           send_macip_acl_interface_list_details (am, reg, sw_if_index,
2857                                                  am->macip_acl_by_sw_if_index
2858                                                  [sw_if_index], mp->context);
2859         }
2860     }
2861 }
2862
2863 static void
2864   vl_api_acl_interface_set_etype_whitelist_t_handler
2865   (vl_api_acl_interface_set_etype_whitelist_t * mp)
2866 {
2867   acl_main_t *am = &acl_main;
2868   vl_api_acl_interface_set_etype_whitelist_reply_t *rmp;
2869   int rv = 0;
2870   int i;
2871   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2872   u32 sw_if_index = ntohl (mp->sw_if_index);
2873   u16 *vec_in = 0, *vec_out = 0;
2874   void *oldheap = acl_set_heap (am);
2875
2876   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2877     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2878   else
2879     {
2880       for (i = 0; i < mp->count; i++)
2881         {
2882           if (i < mp->n_input)
2883             vec_add1 (vec_in, ntohs (mp->whitelist[i]));
2884           else
2885             vec_add1 (vec_out, ntohs (mp->whitelist[i]));
2886         }
2887       rv = acl_set_etype_whitelists (am, sw_if_index, vec_in, vec_out);
2888     }
2889
2890   clib_mem_set_heap (oldheap);
2891   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY);
2892 }
2893
2894 static void
2895 send_acl_interface_etype_whitelist_details (acl_main_t * am,
2896                                             vl_api_registration_t * reg,
2897                                             u32 sw_if_index, u32 context)
2898 {
2899   vl_api_acl_interface_etype_whitelist_details_t *mp;
2900   int msg_size;
2901   int n_input = 0;
2902   int n_output = 0;
2903   int count = 0;
2904   int i = 0;
2905
2906   u16 *whitelist_in = 0;
2907   u16 *whitelist_out = 0;
2908
2909   if (intf_has_etype_whitelist (am, sw_if_index, 0))
2910     whitelist_out =
2911       vec_elt (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
2912
2913   if (intf_has_etype_whitelist (am, sw_if_index, 1))
2914     whitelist_in =
2915       vec_elt (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
2916
2917   if ((0 == whitelist_in) && (0 == whitelist_out))
2918     return;                     /* nothing to do */
2919
2920   void *oldheap = acl_set_heap (am);
2921
2922   n_input = vec_len (whitelist_in);
2923   n_output = vec_len (whitelist_out);
2924   count = n_input + n_output;
2925
2926   msg_size = sizeof (*mp);
2927   msg_size += sizeof (mp->whitelist[0]) * count;
2928
2929   mp = vl_msg_api_alloc (msg_size);
2930   memset (mp, 0, msg_size);
2931   mp->_vl_msg_id =
2932     ntohs (VL_API_ACL_INTERFACE_ETYPE_WHITELIST_DETAILS + am->msg_id_base);
2933
2934   /* fill in the message */
2935   mp->context = context;
2936   mp->sw_if_index = htonl (sw_if_index);
2937   mp->count = count;
2938   mp->n_input = n_input;
2939   for (i = 0; i < n_input; i++)
2940     {
2941       mp->whitelist[i] = htons (whitelist_in[i]);
2942     }
2943   for (i = 0; i < n_output; i++)
2944     {
2945       mp->whitelist[n_input + i] = htons (whitelist_out[i]);
2946     }
2947   clib_mem_set_heap (oldheap);
2948   vl_api_send_msg (reg, (u8 *) mp);
2949 }
2950
2951
2952 static void
2953   vl_api_acl_interface_etype_whitelist_dump_t_handler
2954   (vl_api_acl_interface_list_dump_t * mp)
2955 {
2956   acl_main_t *am = &acl_main;
2957   vnet_sw_interface_t *swif;
2958   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2959
2960   u32 sw_if_index;
2961   vl_api_registration_t *reg;
2962
2963   reg = vl_api_client_index_to_registration (mp->client_index);
2964   if (!reg)
2965     return;
2966
2967   if (mp->sw_if_index == ~0)
2968     {
2969     /* *INDENT-OFF* */
2970     pool_foreach (swif, im->sw_interfaces,
2971     ({
2972       send_acl_interface_etype_whitelist_details(am, reg, swif->sw_if_index, mp->context);
2973     }));
2974     /* *INDENT-ON* */
2975     }
2976   else
2977     {
2978       sw_if_index = ntohl (mp->sw_if_index);
2979       if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2980         send_acl_interface_etype_whitelist_details (am, reg, sw_if_index,
2981                                                     mp->context);
2982     }
2983 }
2984
2985
2986
2987 /* Set up the API message handling tables */
2988 static clib_error_t *
2989 acl_plugin_api_hookup (vlib_main_t * vm)
2990 {
2991   acl_main_t *am = &acl_main;
2992 #define _(N,n)                                                  \
2993     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
2994                            #n,                                  \
2995                            vl_api_##n##_t_handler,              \
2996                            vl_noop_handler,                     \
2997                            vl_api_##n##_t_endian,               \
2998                            vl_api_##n##_t_print,                \
2999                            sizeof(vl_api_##n##_t), 1);
3000   foreach_acl_plugin_api_msg;
3001 #undef _
3002
3003   return 0;
3004 }
3005
3006 #define vl_msg_name_crc_list
3007 #include <acl/acl_all_api_h.h>
3008 #undef vl_msg_name_crc_list
3009
3010 static void
3011 setup_message_id_table (acl_main_t * am, api_main_t * apim)
3012 {
3013 #define _(id,n,crc) \
3014   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
3015   foreach_vl_msg_name_crc_acl;
3016 #undef _
3017 }
3018
3019 static void
3020 acl_setup_fa_nodes (void)
3021 {
3022   vlib_main_t *vm = vlib_get_main ();
3023   acl_main_t *am = &acl_main;
3024   vlib_node_t *n, *n4, *n6;
3025
3026   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
3027   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
3028   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
3029
3030
3031   am->l2_input_classify_next_acl_ip4 =
3032     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
3033   am->l2_input_classify_next_acl_ip6 =
3034     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
3035
3036   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
3037                                l2input_get_feat_names (),
3038                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
3039
3040   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
3041                                l2input_get_feat_names (),
3042                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
3043
3044
3045   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
3046   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
3047   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
3048
3049   am->l2_output_classify_next_acl_ip4 =
3050     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
3051   am->l2_output_classify_next_acl_ip6 =
3052     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
3053
3054   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
3055                                l2output_get_feat_names (),
3056                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
3057
3058   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
3059                                l2output_get_feat_names (),
3060                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
3061 }
3062
3063 static void
3064 acl_set_timeout_sec (int timeout_type, u32 value)
3065 {
3066   acl_main_t *am = &acl_main;
3067   clib_time_t *ct = &am->vlib_main->clib_time;
3068
3069   if (timeout_type < ACL_N_TIMEOUTS)
3070     {
3071       am->session_timeout_sec[timeout_type] = value;
3072     }
3073   else
3074     {
3075       clib_warning ("Unknown timeout type %d", timeout_type);
3076       return;
3077     }
3078   am->session_timeout[timeout_type] =
3079     (u64) (((f64) value) / ct->seconds_per_clock);
3080 }
3081
3082 static void
3083 acl_set_session_max_entries (u32 value)
3084 {
3085   acl_main_t *am = &acl_main;
3086   am->fa_conn_table_max_entries = value;
3087 }
3088
3089 static int
3090 acl_set_skip_ipv6_eh (u32 eh, u32 value)
3091 {
3092   acl_main_t *am = &acl_main;
3093
3094   if ((eh < 256) && (value < 2))
3095     {
3096       am->fa_ipv6_known_eh_bitmap =
3097         clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
3098       return 1;
3099     }
3100   else
3101     return 0;
3102 }
3103
3104
3105 static clib_error_t *
3106 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
3107 {
3108   acl_main_t *am = &acl_main;
3109   if (0 == am->acl_mheap)
3110     {
3111       /* ACL heap is not initialized, so definitely nothing to do. */
3112       return 0;
3113     }
3114   if (0 == is_add)
3115     {
3116       int may_clear_sessions = 1;
3117       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
3118                                  ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
3119                                  sw_if_index);
3120       /* also unapply any ACLs in case the users did not do so. */
3121       macip_acl_interface_del_acl (am, sw_if_index);
3122       acl_interface_reset_inout_acls (sw_if_index, 0, &may_clear_sessions);
3123       acl_interface_reset_inout_acls (sw_if_index, 1, &may_clear_sessions);
3124     }
3125   return 0;
3126 }
3127
3128 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
3129
3130
3131
3132 static clib_error_t *
3133 acl_set_aclplugin_fn (vlib_main_t * vm,
3134                       unformat_input_t * input, vlib_cli_command_t * cmd)
3135 {
3136   clib_error_t *error = 0;
3137   u32 timeout = 0;
3138   u32 val = 0;
3139   u32 eh_val = 0;
3140   uword memory_size = 0;
3141   acl_main_t *am = &acl_main;
3142
3143   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
3144     {
3145       if (!acl_set_skip_ipv6_eh (eh_val, val))
3146         {
3147           error = clib_error_return (0, "expecting eh=0..255, value=0..1");
3148         }
3149       goto done;
3150     }
3151   if (unformat (input, "use-hash-acl-matching %u", &val))
3152     {
3153       am->use_hash_acl_matching = (val != 0);
3154       goto done;
3155     }
3156   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
3157     {
3158       am->l4_match_nonfirst_fragment = (val != 0);
3159       goto done;
3160     }
3161   if (unformat (input, "event-trace"))
3162     {
3163       if (!unformat (input, "%u", &val))
3164         {
3165           error = clib_error_return (0,
3166                                      "expecting trace level, got `%U`",
3167                                      format_unformat_error, input);
3168           goto done;
3169         }
3170       else
3171         {
3172           am->trace_acl = val;
3173           goto done;
3174         }
3175     }
3176   if (unformat (input, "heap"))
3177     {
3178       if (unformat (input, "main"))
3179         {
3180           if (unformat (input, "validate %u", &val))
3181             acl_plugin_acl_set_validate_heap (am, val);
3182           else if (unformat (input, "trace %u", &val))
3183             acl_plugin_acl_set_trace_heap (am, val);
3184           goto done;
3185         }
3186       else if (unformat (input, "hash"))
3187         {
3188           if (unformat (input, "validate %u", &val))
3189             acl_plugin_hash_acl_set_validate_heap (val);
3190           else if (unformat (input, "trace %u", &val))
3191             acl_plugin_hash_acl_set_trace_heap (val);
3192           goto done;
3193         }
3194       goto done;
3195     }
3196   if (unformat (input, "session"))
3197     {
3198       if (unformat (input, "table"))
3199         {
3200           /* The commands here are for tuning/testing. No user-serviceable parts inside */
3201           if (unformat (input, "max-entries"))
3202             {
3203               if (!unformat (input, "%u", &val))
3204                 {
3205                   error = clib_error_return (0,
3206                                              "expecting maximum number of entries, got `%U`",
3207                                              format_unformat_error, input);
3208                   goto done;
3209                 }
3210               else
3211                 {
3212                   acl_set_session_max_entries (val);
3213                   goto done;
3214                 }
3215             }
3216           if (unformat (input, "hash-table-buckets"))
3217             {
3218               if (!unformat (input, "%u", &val))
3219                 {
3220                   error = clib_error_return (0,
3221                                              "expecting maximum number of hash table buckets, got `%U`",
3222                                              format_unformat_error, input);
3223                   goto done;
3224                 }
3225               else
3226                 {
3227                   am->fa_conn_table_hash_num_buckets = val;
3228                   goto done;
3229                 }
3230             }
3231           if (unformat (input, "hash-table-memory"))
3232             {
3233               if (!unformat (input, "%U", unformat_memory_size, &memory_size))
3234                 {
3235                   error = clib_error_return (0,
3236                                              "expecting maximum amount of hash table memory, got `%U`",
3237                                              format_unformat_error, input);
3238                   goto done;
3239                 }
3240               else
3241                 {
3242                   am->fa_conn_table_hash_memory_size = memory_size;
3243                   goto done;
3244                 }
3245             }
3246           if (unformat (input, "event-trace"))
3247             {
3248               if (!unformat (input, "%u", &val))
3249                 {
3250                   error = clib_error_return (0,
3251                                              "expecting trace level, got `%U`",
3252                                              format_unformat_error, input);
3253                   goto done;
3254                 }
3255               else
3256                 {
3257                   am->trace_sessions = val;
3258                   goto done;
3259                 }
3260             }
3261           goto done;
3262         }
3263       if (unformat (input, "timeout"))
3264         {
3265           if (unformat (input, "udp"))
3266             {
3267               if (unformat (input, "idle"))
3268                 {
3269                   if (!unformat (input, "%u", &timeout))
3270                     {
3271                       error = clib_error_return (0,
3272                                                  "expecting timeout value in seconds, got `%U`",
3273                                                  format_unformat_error,
3274                                                  input);
3275                       goto done;
3276                     }
3277                   else
3278                     {
3279                       acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
3280                       goto done;
3281                     }
3282                 }
3283             }
3284           if (unformat (input, "tcp"))
3285             {
3286               if (unformat (input, "idle"))
3287                 {
3288                   if (!unformat (input, "%u", &timeout))
3289                     {
3290                       error = clib_error_return (0,
3291                                                  "expecting timeout value in seconds, got `%U`",
3292                                                  format_unformat_error,
3293                                                  input);
3294                       goto done;
3295                     }
3296                   else
3297                     {
3298                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
3299                       goto done;
3300                     }
3301                 }
3302               if (unformat (input, "transient"))
3303                 {
3304                   if (!unformat (input, "%u", &timeout))
3305                     {
3306                       error = clib_error_return (0,
3307                                                  "expecting timeout value in seconds, got `%U`",
3308                                                  format_unformat_error,
3309                                                  input);
3310                       goto done;
3311                     }
3312                   else
3313                     {
3314                       acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
3315                                            timeout);
3316                       goto done;
3317                     }
3318                 }
3319             }
3320           goto done;
3321         }
3322     }
3323 done:
3324   return error;
3325 }
3326
3327 static u8 *
3328 my_format_mac_address (u8 * s, va_list * args)
3329 {
3330   u8 *a = va_arg (*args, u8 *);
3331   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
3332                  a[0], a[1], a[2], a[3], a[4], a[5]);
3333 }
3334
3335 static inline u8 *
3336 my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
3337 {
3338   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
3339
3340   out = format (out, "%s action %d ip %U/%d mac %U mask %U",
3341                 a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
3342                 format_ip46_address, &a->src_ip_addr,
3343                 a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
3344                 a->src_prefixlen,
3345                 my_format_mac_address, a->src_mac,
3346                 my_format_mac_address, a->src_mac_mask);
3347   return (out);
3348 }
3349
3350 static void
3351 macip_acl_print (acl_main_t * am, u32 macip_acl_index)
3352 {
3353   vlib_main_t *vm = am->vlib_main;
3354   int i;
3355
3356   /* Don't try to print someone else's memory */
3357   if (macip_acl_index > vec_len (am->macip_acls))
3358     return;
3359
3360   macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
3361   int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
3362
3363   vlib_cli_output (vm,
3364                    "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
3365                    macip_acl_index, a->count, vec_len (a->rules), a->tag,
3366                    free_pool_slot);
3367   vlib_cli_output (vm,
3368                    "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
3369                    a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
3370   vlib_cli_output (vm,
3371                    "  out_ip4_table_index %d, out_ip6_table_index %d, out_l2_table_index %d\n",
3372                    a->out_ip4_table_index, a->out_ip6_table_index,
3373                    a->out_l2_table_index);
3374   for (i = 0; i < vec_len (a->rules); i++)
3375     vlib_cli_output (vm, "    rule %d: %U\n", i,
3376                      my_macip_acl_rule_t_pretty_format,
3377                      vec_elt_at_index (a->rules, i));
3378
3379 }
3380
3381 static clib_error_t *
3382 acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
3383                                  unformat_input_t *
3384                                  input, vlib_cli_command_t * cmd)
3385 {
3386   clib_error_t *error = 0;
3387   acl_main_t *am = &acl_main;
3388   int i;
3389   u32 acl_index = ~0;
3390
3391   (void) unformat (input, "index %u", &acl_index);
3392
3393   for (i = 0; i < vec_len (am->macip_acls); i++)
3394     {
3395       /* Don't attempt to show the ACLs that do not exist */
3396       if (pool_is_free_index (am->macip_acls, i))
3397         continue;
3398
3399       if ((acl_index != ~0) && (acl_index != i))
3400         {
3401           continue;
3402         }
3403
3404       macip_acl_print (am, i);
3405       if (i < vec_len (am->sw_if_index_vec_by_macip_acl))
3406         {
3407           vlib_cli_output (vm, "  applied on sw_if_index: %d\n",
3408                            vec_elt (am->sw_if_index_vec_by_macip_acl, i));
3409         }
3410     }
3411
3412   return error;
3413 }
3414
3415 static clib_error_t *
3416 acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
3417                                        unformat_input_t *
3418                                        input, vlib_cli_command_t * cmd)
3419 {
3420   clib_error_t *error = 0;
3421   acl_main_t *am = &acl_main;
3422   int i;
3423   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
3424     {
3425       vlib_cli_output (vm, "  sw_if_index %d: %d\n", i,
3426                        vec_elt (am->macip_acl_by_sw_if_index, i));
3427     }
3428   return error;
3429 }
3430
3431 static void
3432 acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
3433 {
3434   u32 i;
3435   vlib_main_t *vm = am->vlib_main;
3436
3437   for (i = 0; i < vec_len (am->acls); i++)
3438     {
3439       if (acl_is_not_defined (am, i))
3440         {
3441           /* don't attempt to show the ACLs that do not exist */
3442           continue;
3443         }
3444       if ((acl_index != ~0) && (acl_index != i))
3445         {
3446           continue;
3447         }
3448       acl_print_acl (vm, am, i);
3449
3450       if (i < vec_len (am->input_sw_if_index_vec_by_acl))
3451         {
3452           vlib_cli_output (vm, "  applied inbound on sw_if_index: %U\n",
3453                            format_vec32, am->input_sw_if_index_vec_by_acl[i],
3454                            "%d");
3455         }
3456       if (i < vec_len (am->output_sw_if_index_vec_by_acl))
3457         {
3458           vlib_cli_output (vm, "  applied outbound on sw_if_index: %U\n",
3459                            format_vec32, am->output_sw_if_index_vec_by_acl[i],
3460                            "%d");
3461         }
3462       if (i < vec_len (am->lc_index_vec_by_acl))
3463         {
3464           vlib_cli_output (vm, "  used in lookup context index: %U\n",
3465                            format_vec32, am->lc_index_vec_by_acl[i], "%d");
3466         }
3467     }
3468 }
3469
3470 static clib_error_t *
3471 acl_show_aclplugin_acl_fn (vlib_main_t * vm,
3472                            unformat_input_t * input, vlib_cli_command_t * cmd)
3473 {
3474   clib_error_t *error = 0;
3475   acl_main_t *am = &acl_main;
3476
3477   u32 acl_index = ~0;
3478   (void) unformat (input, "index %u", &acl_index);
3479
3480   acl_plugin_show_acl (am, acl_index);
3481   return error;
3482 }
3483
3484 static clib_error_t *
3485 acl_show_aclplugin_lookup_context_fn (vlib_main_t * vm,
3486                                       unformat_input_t * input,
3487                                       vlib_cli_command_t * cmd)
3488 {
3489   clib_error_t *error = 0;
3490
3491   u32 lc_index = ~0;
3492   (void) unformat (input, "index %u", &lc_index);
3493
3494   acl_plugin_show_lookup_context (lc_index);
3495   return error;
3496 }
3497
3498 static clib_error_t *
3499 acl_show_aclplugin_lookup_user_fn (vlib_main_t * vm,
3500                                    unformat_input_t * input,
3501                                    vlib_cli_command_t * cmd)
3502 {
3503   clib_error_t *error = 0;
3504
3505   u32 lc_index = ~0;
3506   (void) unformat (input, "index %u", &lc_index);
3507
3508   acl_plugin_show_lookup_user (lc_index);
3509   return error;
3510 }
3511
3512
3513 static void
3514 acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl,
3515                            int detail)
3516 {
3517   vlib_main_t *vm = am->vlib_main;
3518   u32 swi;
3519   u32 *pj;
3520   for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
3521        (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
3522     {
3523       /* if we need a particular interface, skip all the others */
3524       if ((sw_if_index != ~0) && (sw_if_index != swi))
3525         continue;
3526
3527       vlib_cli_output (vm, "sw_if_index %d:\n", swi);
3528
3529       if (intf_has_etype_whitelist (am, swi, 1))
3530         {
3531           vlib_cli_output (vm, "  input etype whitelist: %U", format_vec16,
3532                            am->input_etype_whitelist_by_sw_if_index[swi],
3533                            "%04x");
3534         }
3535       if (intf_has_etype_whitelist (am, swi, 0))
3536         {
3537           vlib_cli_output (vm, " output etype whitelist: %U", format_vec16,
3538                            am->output_etype_whitelist_by_sw_if_index[swi],
3539                            "%04x");
3540         }
3541
3542       if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
3543           (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
3544         {
3545           vlib_cli_output (vm, "  input acl(s): %U", format_vec32,
3546                            am->input_acl_vec_by_sw_if_index[swi], "%d");
3547           if (show_acl)
3548             {
3549               vlib_cli_output (vm, "\n");
3550               vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
3551               {
3552                 acl_print_acl (vm, am, *pj);
3553               }
3554               vlib_cli_output (vm, "\n");
3555             }
3556         }
3557
3558       if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
3559           (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
3560         {
3561           vlib_cli_output (vm, "  output acl(s): %U", format_vec32,
3562                            am->output_acl_vec_by_sw_if_index[swi], "%d");
3563           if (show_acl)
3564             {
3565               vlib_cli_output (vm, "\n");
3566               vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
3567               {
3568                 acl_print_acl (vm, am, *pj);
3569               }
3570               vlib_cli_output (vm, "\n");
3571             }
3572         }
3573       if (detail && (swi < vec_len (am->input_lc_index_by_sw_if_index)))
3574         {
3575           vlib_cli_output (vm, "   input lookup context index: %d",
3576                            am->input_lc_index_by_sw_if_index[swi]);
3577         }
3578       if (detail && (swi < vec_len (am->output_lc_index_by_sw_if_index)))
3579         {
3580           vlib_cli_output (vm, "  output lookup context index: %d",
3581                            am->output_lc_index_by_sw_if_index[swi]);
3582         }
3583     }
3584
3585 }
3586
3587
3588 static clib_error_t *
3589 acl_show_aclplugin_decode_5tuple_fn (vlib_main_t * vm,
3590                                      unformat_input_t * input,
3591                                      vlib_cli_command_t * cmd)
3592 {
3593   clib_error_t *error = 0;
3594   u64 five_tuple[6] = { 0, 0, 0, 0, 0, 0 };
3595
3596   if (unformat
3597       (input, "%llx %llx %llx %llx %llx %llx", &five_tuple[0], &five_tuple[1],
3598        &five_tuple[2], &five_tuple[3], &five_tuple[4], &five_tuple[5]))
3599     vlib_cli_output (vm, "5-tuple structure decode: %U\n\n",
3600                      format_acl_plugin_5tuple, five_tuple);
3601   else
3602     error = clib_error_return (0, "expecting 6 hex integers");
3603   return error;
3604 }
3605
3606
3607 static clib_error_t *
3608 acl_show_aclplugin_interface_fn (vlib_main_t * vm,
3609                                  unformat_input_t *
3610                                  input, vlib_cli_command_t * cmd)
3611 {
3612   clib_error_t *error = 0;
3613   acl_main_t *am = &acl_main;
3614
3615   u32 sw_if_index = ~0;
3616   (void) unformat (input, "sw_if_index %u", &sw_if_index);
3617   int show_acl = unformat (input, "acl");
3618   int detail = unformat (input, "detail");
3619
3620   acl_plugin_show_interface (am, sw_if_index, show_acl, detail);
3621   return error;
3622 }
3623
3624 static clib_error_t *
3625 acl_show_aclplugin_memory_fn (vlib_main_t * vm,
3626                               unformat_input_t * input,
3627                               vlib_cli_command_t * cmd)
3628 {
3629   clib_error_t *error = 0;
3630   acl_main_t *am = &acl_main;
3631
3632   vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
3633   if (am->acl_mheap)
3634     {
3635       vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
3636     }
3637   else
3638     {
3639       vlib_cli_output (vm, " Not initialized\n");
3640     }
3641   vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
3642   if (am->hash_lookup_mheap)
3643     {
3644       vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
3645     }
3646   else
3647     {
3648       vlib_cli_output (vm, " Not initialized\n");
3649     }
3650   return error;
3651 }
3652
3653 static void
3654 acl_plugin_show_sessions (acl_main_t * am,
3655                           u32 show_session_thread_id,
3656                           u32 show_session_session_index)
3657 {
3658   vlib_main_t *vm = am->vlib_main;
3659   u16 wk;
3660   vnet_interface_main_t *im = &am->vnet_main->interface_main;
3661   vnet_sw_interface_t *swif;
3662
3663   {
3664     u64 n_adds = am->fa_session_total_adds;
3665     u64 n_dels = am->fa_session_total_dels;
3666     vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
3667                      n_dels, n_adds - n_dels);
3668   }
3669   vlib_cli_output (vm, "\n\nPer-thread data:");
3670   for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3671     {
3672       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3673       vlib_cli_output (vm, "Thread #%d:", wk);
3674       if (show_session_thread_id == wk
3675           && show_session_session_index < pool_len (pw->fa_sessions_pool))
3676         {
3677           vlib_cli_output (vm, "  session index %u:",
3678                            show_session_session_index);
3679           fa_session_t *sess =
3680             pw->fa_sessions_pool + show_session_session_index;
3681           u64 *m = (u64 *) & sess->info;
3682           vlib_cli_output (vm,
3683                            "    info: %016llx %016llx %016llx %016llx %016llx %016llx",
3684                            m[0], m[1], m[2], m[3], m[4], m[5]);
3685           vlib_cli_output (vm, "    sw_if_index: %u", sess->sw_if_index);
3686           vlib_cli_output (vm, "    tcp_flags_seen: %x",
3687                            sess->tcp_flags_seen.as_u16);
3688           vlib_cli_output (vm, "    last active time: %lu",
3689                            sess->last_active_time);
3690           vlib_cli_output (vm, "    thread index: %u", sess->thread_index);
3691           vlib_cli_output (vm, "    link enqueue time: %lu",
3692                            sess->link_enqueue_time);
3693           vlib_cli_output (vm, "    link next index: %u",
3694                            sess->link_next_idx);
3695           vlib_cli_output (vm, "    link prev index: %u",
3696                            sess->link_prev_idx);
3697           vlib_cli_output (vm, "    link list id: %u", sess->link_list_id);
3698         }
3699       vlib_cli_output (vm, "  connection add/del stats:", wk);
3700       pool_foreach (swif, im->sw_interfaces, (
3701                                                {
3702                                                u32 sw_if_index =
3703                                                swif->sw_if_index;
3704                                                u64 n_adds =
3705                                                sw_if_index <
3706                                                vec_len
3707                                                (pw->fa_session_adds_by_sw_if_index)
3708                                                ?
3709                                                pw->fa_session_adds_by_sw_if_index
3710                                                [sw_if_index] : 0;
3711                                                u64 n_dels =
3712                                                sw_if_index <
3713                                                vec_len
3714                                                (pw->fa_session_dels_by_sw_if_index)
3715                                                ?
3716                                                pw->fa_session_dels_by_sw_if_index
3717                                                [sw_if_index] : 0;
3718                                                vlib_cli_output (vm,
3719                                                                 "    sw_if_index %d: add %lu - del %lu = %lu",
3720                                                                 sw_if_index,
3721                                                                 n_adds,
3722                                                                 n_dels,
3723                                                                 n_adds -
3724                                                                 n_dels);
3725                                                }
3726                     ));
3727
3728       vlib_cli_output (vm, "  connection timeout type lists:", wk);
3729       u8 tt = 0;
3730       for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
3731         {
3732           u32 head_session_index = pw->fa_conn_list_head[tt];
3733           vlib_cli_output (vm, "  fa_conn_list_head[%d]: %d", tt,
3734                            head_session_index);
3735           if (~0 != head_session_index)
3736             {
3737               fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
3738               vlib_cli_output (vm, "    last active time: %lu",
3739                                sess->last_active_time);
3740               vlib_cli_output (vm, "    link enqueue time: %lu",
3741                                sess->link_enqueue_time);
3742             }
3743         }
3744
3745       vlib_cli_output (vm, "  Next expiry time: %lu", pw->next_expiry_time);
3746       vlib_cli_output (vm, "  Requeue until time: %lu",
3747                        pw->requeue_until_time);
3748       vlib_cli_output (vm, "  Current time wait interval: %lu",
3749                        pw->current_time_wait_interval);
3750       vlib_cli_output (vm, "  Count of deleted sessions: %lu",
3751                        pw->cnt_deleted_sessions);
3752       vlib_cli_output (vm, "  Delete already deleted: %lu",
3753                        pw->cnt_already_deleted_sessions);
3754       vlib_cli_output (vm, "  Session timers restarted: %lu",
3755                        pw->cnt_session_timer_restarted);
3756       vlib_cli_output (vm, "  Swipe until this time: %lu",
3757                        pw->swipe_end_time);
3758       vlib_cli_output (vm, "  sw_if_index serviced bitmap: %U",
3759                        format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
3760       vlib_cli_output (vm, "  pending clear intfc bitmap : %U",
3761                        format_bitmap_hex,
3762                        pw->pending_clear_sw_if_index_bitmap);
3763       vlib_cli_output (vm, "  clear in progress: %u", pw->clear_in_process);
3764       vlib_cli_output (vm, "  interrupt is pending: %d",
3765                        pw->interrupt_is_pending);
3766       vlib_cli_output (vm, "  interrupt is needed: %d",
3767                        pw->interrupt_is_needed);
3768       vlib_cli_output (vm, "  interrupt is unwanted: %d",
3769                        pw->interrupt_is_unwanted);
3770       vlib_cli_output (vm, "  interrupt generation: %d",
3771                        pw->interrupt_generation);
3772     }
3773   vlib_cli_output (vm, "\n\nConn cleaner thread counters:");
3774 #define _(cnt, desc) vlib_cli_output(vm, "             %20lu: %s", am->cnt, desc);
3775   foreach_fa_cleaner_counter;
3776 #undef _
3777   vlib_cli_output (vm, "Interrupt generation: %d",
3778                    am->fa_interrupt_generation);
3779   vlib_cli_output (vm,
3780                    "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
3781                    am->fa_min_deleted_sessions_per_interval,
3782                    am->fa_max_deleted_sessions_per_interval,
3783                    am->fa_cleaner_wait_time_increment * 1000.0,
3784                    ((f64) am->fa_current_cleaner_timer_wait_interval) *
3785                    1000.0 / (f64) vm->clib_time.clocks_per_second);
3786 }
3787
3788 static clib_error_t *
3789 acl_show_aclplugin_sessions_fn (vlib_main_t * vm,
3790                                 unformat_input_t * input,
3791                                 vlib_cli_command_t * cmd)
3792 {
3793   clib_error_t *error = 0;
3794   acl_main_t *am = &acl_main;
3795
3796   u32 show_bihash_verbose = 0;
3797   u32 show_session_thread_id = ~0;
3798   u32 show_session_session_index = ~0;
3799   (void) unformat (input, "thread %u index %u", &show_session_thread_id,
3800                    &show_session_session_index);
3801   (void) unformat (input, "verbose %u", &show_bihash_verbose);
3802
3803   acl_plugin_show_sessions (am, show_session_thread_id,
3804                             show_session_session_index);
3805   show_fa_sessions_hash (vm, show_bihash_verbose);
3806   return error;
3807 }
3808
3809 static clib_error_t *
3810 acl_show_aclplugin_tables_fn (vlib_main_t * vm,
3811                               unformat_input_t * input,
3812                               vlib_cli_command_t * cmd)
3813 {
3814   clib_error_t *error = 0;
3815
3816   u32 acl_index = ~0;
3817   u32 sw_if_index = ~0;
3818   int show_acl_hash_info = 0;
3819   int show_applied_info = 0;
3820   int show_mask_type = 0;
3821   int show_bihash = 0;
3822   u32 show_bihash_verbose = 0;
3823
3824   if (unformat (input, "acl"))
3825     {
3826       show_acl_hash_info = 1;
3827       /* mask-type is handy to see as well right there */
3828       show_mask_type = 1;
3829       unformat (input, "index %u", &acl_index);
3830     }
3831   else if (unformat (input, "applied"))
3832     {
3833       show_applied_info = 1;
3834       unformat (input, "sw_if_index %u", &sw_if_index);
3835     }
3836   else if (unformat (input, "mask"))
3837     {
3838       show_mask_type = 1;
3839     }
3840   else if (unformat (input, "hash"))
3841     {
3842       show_bihash = 1;
3843       unformat (input, "verbose %u", &show_bihash_verbose);
3844     }
3845
3846   if (!
3847       (show_mask_type || show_acl_hash_info || show_applied_info
3848        || show_bihash))
3849     {
3850       /* if no qualifiers specified, show all */
3851       show_mask_type = 1;
3852       show_acl_hash_info = 1;
3853       show_applied_info = 1;
3854       show_bihash = 1;
3855     }
3856   if (show_mask_type)
3857     acl_plugin_show_tables_mask_type ();
3858   if (show_acl_hash_info)
3859     acl_plugin_show_tables_acl_hash_info (acl_index);
3860   if (show_applied_info)
3861     acl_plugin_show_tables_applied_info (sw_if_index);
3862   if (show_bihash)
3863     acl_plugin_show_tables_bihash (show_bihash_verbose);
3864
3865   return error;
3866 }
3867
3868 static clib_error_t *
3869 acl_clear_aclplugin_fn (vlib_main_t * vm,
3870                         unformat_input_t * input, vlib_cli_command_t * cmd)
3871 {
3872   clib_error_t *error = 0;
3873   acl_main_t *am = &acl_main;
3874   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
3875                              ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
3876   return error;
3877 }
3878
3879  /* *INDENT-OFF* */
3880 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
3881     .path = "set acl-plugin",
3882     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
3883     .function = acl_set_aclplugin_fn,
3884 };
3885
3886 VLIB_CLI_COMMAND (aclplugin_show_acl_command, static) = {
3887     .path = "show acl-plugin acl",
3888     .short_help = "show acl-plugin acl [index N]",
3889     .function = acl_show_aclplugin_acl_fn,
3890 };
3891
3892 VLIB_CLI_COMMAND (aclplugin_show_lookup_context_command, static) = {
3893     .path = "show acl-plugin lookup context",
3894     .short_help = "show acl-plugin lookup context [index N]",
3895     .function = acl_show_aclplugin_lookup_context_fn,
3896 };
3897
3898 VLIB_CLI_COMMAND (aclplugin_show_lookup_user_command, static) = {
3899     .path = "show acl-plugin lookup user",
3900     .short_help = "show acl-plugin lookup user [index N]",
3901     .function = acl_show_aclplugin_lookup_user_fn,
3902 };
3903
3904 VLIB_CLI_COMMAND (aclplugin_show_decode_5tuple_command, static) = {
3905     .path = "show acl-plugin decode 5tuple",
3906     .short_help = "show acl-plugin decode 5tuple XXXX XXXX XXXX XXXX XXXX XXXX",
3907     .function = acl_show_aclplugin_decode_5tuple_fn,
3908 };
3909
3910 VLIB_CLI_COMMAND (aclplugin_show_interface_command, static) = {
3911     .path = "show acl-plugin interface",
3912     .short_help = "show acl-plugin interface [sw_if_index N] [acl]",
3913     .function = acl_show_aclplugin_interface_fn,
3914 };
3915
3916 VLIB_CLI_COMMAND (aclplugin_show_memory_command, static) = {
3917     .path = "show acl-plugin memory",
3918     .short_help = "show acl-plugin memory",
3919     .function = acl_show_aclplugin_memory_fn,
3920 };
3921
3922 VLIB_CLI_COMMAND (aclplugin_show_sessions_command, static) = {
3923     .path = "show acl-plugin sessions",
3924     .short_help = "show acl-plugin sessions",
3925     .function = acl_show_aclplugin_sessions_fn,
3926 };
3927
3928 VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
3929     .path = "show acl-plugin tables",
3930     .short_help = "show acl-plugin tables [ acl [index N] | applied [ sw_if_index N ] | mask | hash [verbose N] ]",
3931     .function = acl_show_aclplugin_tables_fn,
3932 };
3933
3934 VLIB_CLI_COMMAND (aclplugin_show_macip_acl_command, static) = {
3935     .path = "show acl-plugin macip acl",
3936     .short_help = "show acl-plugin macip acl [index N]",
3937     .function = acl_show_aclplugin_macip_acl_fn,
3938 };
3939
3940 VLIB_CLI_COMMAND (aclplugin_show_macip_interface_command, static) = {
3941     .path = "show acl-plugin macip interface",
3942     .short_help = "show acl-plugin macip interface",
3943     .function = acl_show_aclplugin_macip_interface_fn,
3944 };
3945
3946 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
3947     .path = "clear acl-plugin sessions",
3948     .short_help = "clear acl-plugin sessions",
3949     .function = acl_clear_aclplugin_fn,
3950 };
3951 /* *INDENT-ON* */
3952
3953 static clib_error_t *
3954 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
3955 {
3956   acl_main_t *am = &acl_main;
3957   u32 conn_table_hash_buckets;
3958   u32 conn_table_hash_memory_size;
3959   u32 conn_table_max_entries;
3960   u32 main_heap_size;
3961   u32 hash_heap_size;
3962   u32 hash_lookup_hash_buckets;
3963   u32 hash_lookup_hash_memory;
3964
3965   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3966     {
3967       if (unformat
3968           (input, "connection hash buckets %d", &conn_table_hash_buckets))
3969         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
3970       else if (unformat (input, "connection hash memory %d",
3971                          &conn_table_hash_memory_size))
3972         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
3973       else if (unformat (input, "connection count max %d",
3974                          &conn_table_max_entries))
3975         am->fa_conn_table_max_entries = conn_table_max_entries;
3976       else if (unformat (input, "main heap size %d", &main_heap_size))
3977         am->acl_mheap_size = main_heap_size;
3978       else if (unformat (input, "hash lookup heap size %d", &hash_heap_size))
3979         am->hash_lookup_mheap_size = hash_heap_size;
3980       else if (unformat (input, "hash lookup hash buckets %d",
3981                          &hash_lookup_hash_buckets))
3982         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
3983       else if (unformat (input, "hash lookup hash memory %d",
3984                          &hash_lookup_hash_memory))
3985         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
3986       else
3987         return clib_error_return (0, "unknown input '%U'",
3988                                   format_unformat_error, input);
3989     }
3990   return 0;
3991 }
3992
3993 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
3994
3995 static clib_error_t *
3996 acl_init (vlib_main_t * vm)
3997 {
3998   acl_main_t *am = &acl_main;
3999   clib_error_t *error = 0;
4000   memset (am, 0, sizeof (*am));
4001   am->vlib_main = vm;
4002   am->vnet_main = vnet_get_main ();
4003
4004   u8 *name = format (0, "acl_%08x%c", api_version, 0);
4005
4006   /* Ask for a correctly-sized block of API message decode slots */
4007   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
4008                                             VL_MSG_FIRST_AVAILABLE);
4009
4010   error = acl_plugin_api_hookup (vm);
4011
4012   /* Add our API messages to the global name_crc hash table */
4013   setup_message_id_table (am, &api_main);
4014
4015   vec_free (name);
4016
4017   acl_setup_fa_nodes ();
4018
4019   am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
4020   am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
4021
4022   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
4023   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
4024
4025   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
4026     TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
4027   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
4028     TCP_SESSION_IDLE_TIMEOUT_SEC;
4029   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
4030     UDP_SESSION_IDLE_TIMEOUT_SEC;
4031
4032   am->fa_conn_table_hash_num_buckets =
4033     ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
4034   am->fa_conn_table_hash_memory_size =
4035     ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
4036   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
4037   vlib_thread_main_t *tm = vlib_get_thread_main ();
4038   vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
4039   {
4040     u16 wk;
4041     u8 tt;
4042     for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
4043       {
4044         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
4045         vec_validate (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1);
4046         vec_validate (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1);
4047         for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
4048           {
4049             pw->fa_conn_list_head[tt] = ~0;
4050             pw->fa_conn_list_tail[tt] = ~0;
4051           }
4052       }
4053   }
4054
4055   am->fa_min_deleted_sessions_per_interval =
4056     ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
4057   am->fa_max_deleted_sessions_per_interval =
4058     ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
4059   am->fa_cleaner_wait_time_increment =
4060     ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
4061
4062   am->fa_cleaner_cnt_delete_by_sw_index = 0;
4063   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
4064   am->fa_cleaner_cnt_unknown_event = 0;
4065   am->fa_cleaner_cnt_timer_restarted = 0;
4066   am->fa_cleaner_cnt_wait_with_timeout = 0;
4067
4068
4069 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
4070   foreach_acl_eh
4071 #undef _
4072     am->l4_match_nonfirst_fragment = 1;
4073
4074   /* use the new fancy hash-based matching */
4075   am->use_hash_acl_matching = 1;
4076
4077   am->interface_acl_user_id =
4078     acl_plugin_register_user_module ("interface ACL", "sw_if_index",
4079                                      "is_input");
4080
4081   return error;
4082 }
4083
4084 VLIB_INIT_FUNCTION (acl_init);
4085
4086
4087 /*
4088  * fd.io coding-style-patch-verification: ON
4089  *
4090  * Local Variables:
4091  * eval: (c-set-style "gnu")
4092  * End:
4093  */