ACL-plugin: fix coverity issue
[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/input_acl.h>
24 #include <vpp/app/version.h>
25
26 #include <vlibapi/api.h>
27 #include <vlibmemory/api.h>
28 #include <vlibsocket/api.h>
29
30 /* define message IDs */
31 #include <acl/acl_msg_enum.h>
32
33 /* define message structures */
34 #define vl_typedefs
35 #include <acl/acl_all_api_h.h>
36 #undef vl_typedefs
37
38 /* define generated endian-swappers */
39 #define vl_endianfun
40 #include <acl/acl_all_api_h.h>
41 #undef vl_endianfun
42
43 /* instantiate all the print functions we know about */
44 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #define vl_printfun
46 #include <acl/acl_all_api_h.h>
47 #undef vl_printfun
48
49 /* Get the API version number */
50 #define vl_api_version(n,v) static u32 api_version=(v);
51 #include <acl/acl_all_api_h.h>
52 #undef vl_api_version
53
54 #include "fa_node.h"
55 #include "hash_lookup.h"
56
57 acl_main_t acl_main;
58
59 #define REPLY_MSG_ID_BASE am->msg_id_base
60 #include <vlibapi/api_helper_macros.h>
61
62 /* List of message types that this plugin understands */
63
64 #define foreach_acl_plugin_api_msg              \
65 _(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \
66 _(ACL_PLUGIN_CONTROL_PING, acl_plugin_control_ping) \
67 _(ACL_ADD_REPLACE, acl_add_replace)                             \
68 _(ACL_DEL, acl_del)                             \
69 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
70 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)       \
71 _(ACL_DUMP, acl_dump)  \
72 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
73 _(MACIP_ACL_ADD, macip_acl_add) \
74 _(MACIP_ACL_ADD_REPLACE, macip_acl_add_replace) \
75 _(MACIP_ACL_DEL, macip_acl_del) \
76 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
77 _(MACIP_ACL_DUMP, macip_acl_dump) \
78 _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) \
79 _(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump)
80
81
82 /* *INDENT-OFF* */
83 VLIB_PLUGIN_REGISTER () = {
84     .version = VPP_BUILD_VER,
85     .description = "Access Control Lists",
86 };
87 /* *INDENT-ON* */
88
89
90 static void *
91 acl_set_heap(acl_main_t *am)
92 {
93   if (0 == am->acl_mheap) {
94     am->acl_mheap = mheap_alloc (0 /* use VM */ , am->acl_mheap_size);
95     mheap_t *h = mheap_header (am->acl_mheap);
96     h->flags |= MHEAP_FLAG_THREAD_SAFE;
97   }
98   void *oldheap = clib_mem_set_heap(am->acl_mheap);
99   return oldheap;
100 }
101
102 void
103 acl_plugin_acl_set_validate_heap(acl_main_t *am, int on)
104 {
105   clib_mem_set_heap(acl_set_heap(am));
106   mheap_t *h = mheap_header (am->acl_mheap);
107   if (on) {
108     h->flags |= MHEAP_FLAG_VALIDATE;
109     h->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
110     mheap_validate(h);
111   } else {
112     h->flags &= ~MHEAP_FLAG_VALIDATE;
113     h->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
114   }
115 }
116
117 void
118 acl_plugin_acl_set_trace_heap(acl_main_t *am, int on)
119 {
120   clib_mem_set_heap(acl_set_heap(am));
121   mheap_t *h = mheap_header (am->acl_mheap);
122   if (on) {
123     h->flags |= MHEAP_FLAG_TRACE;
124   } else {
125     h->flags &= ~MHEAP_FLAG_TRACE;
126   }
127 }
128
129 static void
130 vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
131 {
132   acl_main_t *am = &acl_main;
133   vl_api_acl_plugin_get_version_reply_t *rmp;
134   int msg_size = sizeof (*rmp);
135   unix_shared_memory_queue_t *q;
136
137   q = vl_api_client_index_to_input_queue (mp->client_index);
138   if (q == 0)
139     {
140       return;
141     }
142
143   rmp = vl_msg_api_alloc (msg_size);
144   memset (rmp, 0, msg_size);
145   rmp->_vl_msg_id =
146     ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
147   rmp->context = mp->context;
148   rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
149   rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
150
151   vl_msg_api_send_shmem (q, (u8 *) & rmp);
152 }
153
154 static void
155 vl_api_acl_plugin_control_ping_t_handler (vl_api_acl_plugin_control_ping_t * mp)
156 {
157   vl_api_acl_plugin_control_ping_reply_t *rmp;
158   acl_main_t *am = &acl_main;
159   int rv = 0;
160
161   /* *INDENT-OFF* */
162   REPLY_MACRO2 (VL_API_ACL_PLUGIN_CONTROL_PING_REPLY,
163   ({
164     rmp->vpe_pid = ntohl (getpid ());
165   }));
166   /* *INDENT-ON* */
167 }
168
169 static int
170 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
171               u32 * acl_list_index, u8 * tag)
172 {
173   acl_main_t *am = &acl_main;
174   acl_list_t *a;
175   acl_rule_t *r;
176   acl_rule_t *acl_new_rules = 0;
177   int i;
178
179   if (*acl_list_index != ~0)
180     {
181       /* They supplied some number, let's see if this ACL exists */
182       if (pool_is_free_index (am->acls, *acl_list_index))
183         {
184           /* tried to replace a non-existent ACL, no point doing anything */
185           clib_warning("acl-plugin-error: Trying to replace nonexistent ACL %d (tag %s)", *acl_list_index, tag);
186           return -1;
187         }
188     }
189   if (0 == count) {
190     clib_warning("acl-plugin-warning: supplied no rules for ACL %d (tag %s)", *acl_list_index, tag);
191   }
192
193   void *oldheap = acl_set_heap(am);
194
195   /* Create and populate the rules */
196   if (count > 0)
197     vec_validate(acl_new_rules, count-1);
198
199   for (i = 0; i < count; i++)
200     {
201       r = vec_elt_at_index(acl_new_rules, i);
202       memset(r, 0, sizeof(*r));
203       r->is_permit = rules[i].is_permit;
204       r->is_ipv6 = rules[i].is_ipv6;
205       if (r->is_ipv6)
206         {
207           memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src));
208           memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst));
209         }
210       else
211         {
212           memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4));
213           memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4));
214         }
215       r->src_prefixlen = rules[i].src_ip_prefix_len;
216       r->dst_prefixlen = rules[i].dst_ip_prefix_len;
217       r->proto = rules[i].proto;
218       r->src_port_or_type_first = ntohs ( rules[i].srcport_or_icmptype_first );
219       r->src_port_or_type_last = ntohs ( rules[i].srcport_or_icmptype_last );
220       r->dst_port_or_code_first = ntohs ( rules[i].dstport_or_icmpcode_first );
221       r->dst_port_or_code_last = ntohs ( rules[i].dstport_or_icmpcode_last );
222       r->tcp_flags_value = rules[i].tcp_flags_value;
223       r->tcp_flags_mask = rules[i].tcp_flags_mask;
224     }
225
226   if (~0 == *acl_list_index)
227     {
228       /* Get ACL index */
229       pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
230       memset (a, 0, sizeof (*a));
231       /* Will return the newly allocated ACL index */
232       *acl_list_index = a - am->acls;
233     }
234   else
235     {
236       a = am->acls + *acl_list_index;
237       hash_acl_delete(am, *acl_list_index);
238       /* Get rid of the old rules */
239       if (a->rules)
240         vec_free (a->rules);
241     }
242   a->rules = acl_new_rules;
243   a->count = count;
244   memcpy (a->tag, tag, sizeof (a->tag));
245   hash_acl_add(am, *acl_list_index);
246   clib_mem_set_heap (oldheap);
247   return 0;
248 }
249
250 static int
251 acl_del_list (u32 acl_list_index)
252 {
253   acl_main_t *am = &acl_main;
254   acl_list_t *a;
255   int i, ii;
256   if (pool_is_free_index (am->acls, acl_list_index))
257     {
258       return -1;
259     }
260
261   if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
262     if (vec_len(pool_elt_at_index(am->input_sw_if_index_vec_by_acl, acl_list_index)) > 0) {
263       /* ACL is applied somewhere inbound. Refuse to delete */
264       return -1;
265     }
266   }
267   if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
268     if (vec_len(pool_elt_at_index(am->output_sw_if_index_vec_by_acl, acl_list_index)) > 0) {
269       /* ACL is applied somewhere outbound. Refuse to delete */
270       return -1;
271     }
272   }
273
274   void *oldheap = acl_set_heap(am);
275   /* delete any references to the ACL */
276   for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++)
277     {
278       for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]);
279            /* see body */ )
280         {
281           if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii])
282             {
283               vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii);
284             }
285           else
286             {
287               ii++;
288             }
289         }
290     }
291   for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++)
292     {
293       for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]);
294            /* see body */ )
295         {
296           if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii])
297             {
298               vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii);
299             }
300           else
301             {
302               ii++;
303             }
304         }
305     }
306   /* delete the hash table data */
307
308   hash_acl_delete(am, acl_list_index);
309   /* now we can delete the ACL itself */
310   a = pool_elt_at_index (am->acls, acl_list_index);
311   if (a->rules)
312     vec_free (a->rules);
313
314   pool_put (am->acls, a);
315   clib_mem_set_heap (oldheap);
316   return 0;
317 }
318
319 /* Some aids in ASCII graphing the content */
320 #define XX "\377"
321 #define __ "\000"
322 #define _(x)
323 #define v
324
325 u8 ip4_5tuple_mask[] =
326 _("             dmac               smac            etype ")
327 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
328   _("        v ihl totlen   ")
329   _(0x0000)
330   __ __ __ __
331   _("        ident fl+fo    ")
332   _(0x0004)
333   __ __ __ __
334   _("       ttl pr checksum ")
335   _(0x0008)
336   __ XX __ __
337   _("        src address    ")
338   _(0x000C)
339   XX XX XX XX
340   _("        dst address    ")
341   _(0x0010)
342   XX XX XX XX
343   _("L4 T/U  sport dport    ")
344   _(tcpudp)
345   XX XX XX XX
346   _(padpad)
347   __ __ __ __
348   _(padpad)
349   __ __ __ __
350   _(padeth)
351   __ __;
352
353      u8 ip6_5tuple_mask[] =
354        _("             dmac               smac            etype ")
355   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
356   _("        v  tc + flow ")
357   _(0x0000) __ __ __ __
358   _("        plen  nh hl  ")
359   _(0x0004) __ __ XX __
360   _("        src address  ")
361   _(0x0008) XX XX XX XX
362   _(0x000C) XX XX XX XX
363   _(0x0010) XX XX XX XX
364   _(0x0014) XX XX XX XX
365   _("        dst address  ")
366   _(0x0018) XX XX XX XX
367   _(0x001C) XX XX XX XX
368   _(0x0020) XX XX XX XX
369   _(0x0024) XX XX XX XX
370   _("L4T/U  sport dport   ")
371   _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
372
373 #undef XX
374 #undef __
375 #undef _
376 #undef v
377
378      static int count_skip (u8 * p, u32 size)
379 {
380   u64 *p64 = (u64 *) p;
381   /* Be tolerant to null pointer */
382   if (0 == p)
383     return 0;
384
385   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
386     {
387       p64++;
388     }
389   return (p64 - (u64 *) p) / 2;
390 }
391
392 static int
393 acl_classify_add_del_table_tiny (vnet_classify_main_t * cm, u8 * mask,
394                             u32 mask_len, u32 next_table_index,
395                             u32 miss_next_index, u32 * table_index,
396                             int is_add)
397 {
398   u32 nbuckets = 1;
399   u32 memory_size = 2 << 13;
400   u32 skip = count_skip (mask, mask_len);
401   u32 match = (mask_len / 16) - skip;
402   u8 *skip_mask_ptr = mask + 16 * skip;
403   u32 current_data_flag = 0;
404   int current_data_offset = 0;
405
406   if (0 == match)
407     match = 1;
408   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
409   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
410                                       memory_size, skip, match,
411                                       next_table_index, miss_next_index,
412                                       table_index, current_data_flag,
413                                       current_data_offset, is_add,
414                                       1 /* delete_chain */);
415   clib_mem_set_heap (oldheap);
416   return ret;
417 }
418
419 static int
420 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
421                             u32 mask_len, u32 next_table_index,
422                             u32 miss_next_index, u32 * table_index,
423                             int is_add)
424 {
425   u32 nbuckets = 32;
426   u32 memory_size = 2 << 20;
427   u32 skip = count_skip (mask, mask_len);
428   u32 match = (mask_len / 16) - skip;
429   u8 *skip_mask_ptr = mask + 16 * skip;
430   u32 current_data_flag = 0;
431   int current_data_offset = 0;
432
433   if (0 == match)
434     match = 1;
435
436   void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
437   int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
438                                       memory_size, skip, match,
439                                       next_table_index, miss_next_index,
440                                       table_index, current_data_flag,
441                                       current_data_offset, is_add,
442                                       1 /* delete_chain */);
443   clib_mem_set_heap (oldheap);
444   return ret;
445 }
446
447
448 static int
449 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
450 {
451   vnet_classify_main_t *cm = &vnet_classify_main;
452   u32 ip4_table_index = ~0;
453   u32 ip6_table_index = ~0;
454   void *oldheap = acl_set_heap(am);
455
456   vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
457                            sw_if_index, ~0);
458   vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
459                            sw_if_index, ~0);
460
461   /* switch to global heap while calling vnet_* functions */
462   clib_mem_set_heap (cm->vlib_main->heap_base);
463   vnet_l2_input_classify_enable_disable (sw_if_index, 0);
464
465   if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
466     {
467       ip4_table_index =
468         am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
469       am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
470       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
471                                   sizeof (ip4_5tuple_mask) - 1, ~0,
472                                   am->l2_input_classify_next_acl_ip4,
473                                   &ip4_table_index, 0);
474     }
475   if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
476     {
477       ip6_table_index =
478         am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
479       am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
480       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
481                                   sizeof (ip6_5tuple_mask) - 1, ~0,
482                                   am->l2_input_classify_next_acl_ip6,
483                                   &ip6_table_index, 0);
484     }
485   clib_mem_set_heap (oldheap);
486   return 0;
487 }
488
489 static int
490 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
491 {
492   vnet_classify_main_t *cm = &vnet_classify_main;
493   u32 ip4_table_index = ~0;
494   u32 ip6_table_index = ~0;
495   void *oldheap = acl_set_heap(am);
496
497   vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
498                            sw_if_index, ~0);
499   vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
500                            sw_if_index, ~0);
501
502   /* switch to global heap while calling vnet_* functions */
503   clib_mem_set_heap (cm->vlib_main->heap_base);
504
505   vnet_l2_output_classify_enable_disable (sw_if_index, 0);
506
507   if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
508     {
509       ip4_table_index =
510         am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
511       am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
512       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
513                                   sizeof (ip4_5tuple_mask) - 1, ~0,
514                                   am->l2_output_classify_next_acl_ip4,
515                                   &ip4_table_index, 0);
516     }
517   if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
518     {
519       ip6_table_index =
520         am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
521       am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
522       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
523                                   sizeof (ip6_5tuple_mask) - 1, ~0,
524                                   am->l2_output_classify_next_acl_ip6,
525                                   &ip6_table_index, 0);
526     }
527   clib_mem_set_heap (oldheap);
528   return 0;
529 }
530
531 static int
532 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
533 {
534   vnet_classify_main_t *cm = &vnet_classify_main;
535   u32 ip4_table_index = ~0;
536   u32 ip6_table_index = ~0;
537   int rv;
538
539   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
540
541   /* in case there were previous tables attached */
542   acl_unhook_l2_input_classify (am, sw_if_index);
543   rv =
544     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
545                                 sizeof (ip4_5tuple_mask) - 1, ~0,
546                                 am->l2_input_classify_next_acl_ip4,
547                                 &ip4_table_index, 1);
548   if (rv)
549     goto done;
550   rv =
551     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
552                                 sizeof (ip6_5tuple_mask) - 1, ~0,
553                                 am->l2_input_classify_next_acl_ip6,
554                                 &ip6_table_index, 1);
555   if (rv)
556     {
557       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
558                                   sizeof (ip4_5tuple_mask) - 1, ~0,
559                                   am->l2_input_classify_next_acl_ip4,
560                                   &ip4_table_index, 0);
561       goto done;
562     }
563   rv =
564     vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
565                                        ip6_table_index, ~0);
566   clib_warning
567     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
568      sw_if_index, ip4_table_index, ip6_table_index);
569   if (rv)
570     {
571       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
572                                   sizeof (ip6_5tuple_mask) - 1, ~0,
573                                   am->l2_input_classify_next_acl_ip6,
574                                   &ip6_table_index, 0);
575       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
576                                   sizeof (ip4_5tuple_mask) - 1, ~0,
577                                   am->l2_input_classify_next_acl_ip4,
578                                   &ip4_table_index, 0);
579       goto done;
580     }
581
582   am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
583     ip4_table_index;
584   am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
585     ip6_table_index;
586
587   vnet_l2_input_classify_enable_disable (sw_if_index, 1);
588 done:
589   clib_mem_set_heap (prevheap);
590   return rv;
591 }
592
593 static int
594 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
595 {
596   vnet_classify_main_t *cm = &vnet_classify_main;
597   u32 ip4_table_index = ~0;
598   u32 ip6_table_index = ~0;
599   int rv;
600
601   void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
602
603   /* in case there were previous tables attached */
604   acl_unhook_l2_output_classify (am, sw_if_index);
605   rv =
606     acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
607                                 sizeof (ip4_5tuple_mask) - 1, ~0,
608                                 am->l2_output_classify_next_acl_ip4,
609                                 &ip4_table_index, 1);
610   if (rv)
611     goto done;
612   rv =
613     acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
614                                 sizeof (ip6_5tuple_mask) - 1, ~0,
615                                 am->l2_output_classify_next_acl_ip6,
616                                 &ip6_table_index, 1);
617   if (rv)
618     {
619       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
620                                   sizeof (ip4_5tuple_mask) - 1, ~0,
621                                   am->l2_output_classify_next_acl_ip4,
622                                   &ip4_table_index, 0);
623       goto done;
624     }
625   rv =
626     vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
627                                         ip6_table_index, ~0);
628   clib_warning
629     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
630      sw_if_index, ip4_table_index, ip6_table_index);
631   if (rv)
632     {
633       acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
634                                   sizeof (ip6_5tuple_mask) - 1, ~0,
635                                   am->l2_output_classify_next_acl_ip6,
636                                   &ip6_table_index, 0);
637       acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
638                                   sizeof (ip4_5tuple_mask) - 1, ~0,
639                                   am->l2_output_classify_next_acl_ip4,
640                                   &ip4_table_index, 0);
641       goto done;
642     }
643
644   am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
645     ip4_table_index;
646   am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
647     ip6_table_index;
648
649   vnet_l2_output_classify_enable_disable (sw_if_index, 1);
650 done:
651   clib_mem_set_heap (prevheap);
652   return rv;
653 }
654
655
656
657 int
658 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
659                                  int enable_disable)
660 {
661   int rv;
662
663   /* Utterly wrong? */
664   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
665                           sw_if_index))
666     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
667
668   acl_fa_enable_disable(sw_if_index, 1, enable_disable);
669
670   if (enable_disable)
671     {
672       rv = acl_hook_l2_input_classify (am, sw_if_index);
673     }
674   else
675     {
676       rv = acl_unhook_l2_input_classify (am, sw_if_index);
677     }
678
679   return rv;
680 }
681
682 int
683 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
684                                   int enable_disable)
685 {
686   int rv;
687
688   /* Utterly wrong? */
689   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
690                           sw_if_index))
691     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
692
693   acl_fa_enable_disable(sw_if_index, 0, enable_disable);
694
695   if (enable_disable)
696     {
697       rv = acl_hook_l2_output_classify (am, sw_if_index);
698     }
699   else
700     {
701       rv = acl_unhook_l2_output_classify (am, sw_if_index);
702     }
703
704   return rv;
705 }
706
707 static int
708 acl_is_not_defined(acl_main_t *am, u32 acl_list_index)
709 {
710   return (pool_is_free_index (am->acls, acl_list_index));
711 }
712
713
714 static int
715 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
716 {
717   acl_main_t *am = &acl_main;
718   if (acl_is_not_defined(am, acl_list_index)) {
719     /* ACL is not defined. Can not apply */
720     return -1;
721   }
722   void *oldheap = acl_set_heap(am);
723
724   if (is_input)
725     {
726       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
727
728       u32 index = vec_search(am->input_acl_vec_by_sw_if_index[sw_if_index], acl_list_index);
729       if (index < vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index])) {
730         clib_warning("ACL %d is already applied inbound on sw_if_index %d (index %d)",
731                      acl_list_index, sw_if_index, index);
732         /* the entry is already there */
733         clib_mem_set_heap (oldheap);
734         return -1;
735       }
736       /* if there was no ACL applied before, enable the ACL processing */
737       if (vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index]) == 0) {
738         acl_interface_in_enable_disable (am, sw_if_index, 1);
739       }
740       vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
741                1);
742       vec_validate (am->input_sw_if_index_vec_by_acl, acl_list_index);
743       vec_add (am->input_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
744                1);
745     }
746   else
747     {
748       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
749
750       u32 index = vec_search(am->output_acl_vec_by_sw_if_index[sw_if_index], acl_list_index);
751       if (index < vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index])) {
752         clib_warning("ACL %d is already applied outbound on sw_if_index %d (index %d)",
753                      acl_list_index, sw_if_index, index);
754         /* the entry is already there */
755         clib_mem_set_heap (oldheap);
756         return -1;
757       }
758       /* if there was no ACL applied before, enable the ACL processing */
759       if (vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index]) == 0) {
760         acl_interface_out_enable_disable (am, sw_if_index, 1);
761       }
762       vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
763                &acl_list_index, 1);
764       vec_validate (am->output_sw_if_index_vec_by_acl, acl_list_index);
765       vec_add (am->output_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
766                1);
767     }
768   clib_mem_set_heap (oldheap);
769   return 0;
770 }
771
772
773 static int
774 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
775 {
776   acl_main_t *am = &acl_main;
777   int i;
778   int rv = -1;
779   void *oldheap = acl_set_heap(am);
780   if (is_input)
781     {
782       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
783       for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
784            i++)
785         {
786           if (acl_list_index ==
787               am->input_acl_vec_by_sw_if_index[sw_if_index][i])
788             {
789               vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
790               rv = 0;
791               break;
792             }
793         }
794
795       if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
796         u32 index = vec_search(am->input_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
797         if (index < vec_len(am->input_sw_if_index_vec_by_acl[acl_list_index])) {
798           hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
799           vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index], index);
800         }
801       }
802
803       /* If there is no more ACLs applied on an interface, disable ACL processing */
804       if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
805         {
806           acl_interface_in_enable_disable (am, sw_if_index, 0);
807         }
808     }
809   else
810     {
811       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
812       for (i = 0;
813            i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
814         {
815           if (acl_list_index ==
816               am->output_acl_vec_by_sw_if_index[sw_if_index][i])
817             {
818               vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
819               rv = 0;
820               break;
821             }
822         }
823
824       if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
825         u32 index = vec_search(am->output_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
826         if (index < vec_len(am->output_sw_if_index_vec_by_acl[acl_list_index])) {
827           hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
828           vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index], index);
829         }
830       }
831
832       /* If there is no more ACLs applied on an interface, disable ACL processing */
833       if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
834         {
835           acl_interface_out_enable_disable (am, sw_if_index, 0);
836         }
837     }
838   clib_mem_set_heap (oldheap);
839   return rv;
840 }
841
842 static void
843 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
844 {
845   acl_main_t *am = &acl_main;
846   int i;
847   void *oldheap = acl_set_heap(am);
848   if (is_input)
849     {
850       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
851       if (vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0) {
852         acl_interface_in_enable_disable (am, sw_if_index, 0);
853       }
854
855       for(i = vec_len(am->input_acl_vec_by_sw_if_index[sw_if_index])-1; i>=0; i--) {
856         u32 acl_list_index = am->input_acl_vec_by_sw_if_index[sw_if_index][i];
857         hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
858         if (acl_list_index < vec_len(am->input_sw_if_index_vec_by_acl)) {
859           u32 index = vec_search(am->input_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
860           if (index < vec_len(am->input_sw_if_index_vec_by_acl[acl_list_index])) {
861             vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index], index);
862           }
863         }
864       }
865
866       vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
867     }
868   else
869     {
870       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
871       if (vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0) {
872         acl_interface_out_enable_disable (am, sw_if_index, 0);
873       }
874
875       for(i = vec_len(am->output_acl_vec_by_sw_if_index[sw_if_index])-1; i>=0; i--) {
876         u32 acl_list_index = am->output_acl_vec_by_sw_if_index[sw_if_index][i];
877         hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
878         if (acl_list_index < vec_len(am->output_sw_if_index_vec_by_acl)) {
879           u32 index = vec_search(am->output_sw_if_index_vec_by_acl[acl_list_index], sw_if_index);
880           if (index < vec_len(am->output_sw_if_index_vec_by_acl[acl_list_index])) {
881             vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index], index);
882           }
883         }
884       }
885
886       vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
887     }
888   clib_mem_set_heap (oldheap);
889 }
890
891 static int
892 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
893                                  u32 acl_list_index)
894 {
895   int rv = -1;
896   acl_main_t *am = &acl_main;
897   void *oldheap = acl_set_heap(am);
898   if (is_add)
899     {
900       rv =
901         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
902       if (rv == 0)
903         {
904           hash_acl_apply(am, sw_if_index, is_input, acl_list_index);
905         }
906     }
907   else
908     {
909       hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
910       rv =
911         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
912     }
913   clib_mem_set_heap (oldheap);
914   return rv;
915 }
916
917
918 typedef struct
919 {
920   u8 is_ipv6;
921   u8 mac_mask[6];
922   u8 prefix_len;
923   u32 count;
924   u32 table_index;
925   u32 arp_table_index;
926 } macip_match_type_t;
927
928 static u32
929 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
930                        u8 is_ipv6)
931 {
932   u32 i;
933   if (mv)
934     {
935       for (i = 0; i < vec_len (mv); i++)
936         {
937           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
938               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
939             {
940               return i;
941             }
942         }
943     }
944   return ~0;
945 }
946
947
948 /* Get metric used to sort match types.
949    The more specific and the more often seen - the bigger the metric */
950 static int
951 match_type_metric (macip_match_type_t * m)
952 {
953    unsigned int mac_bits_set = 0;
954    unsigned int mac_byte;
955    int i;
956    for (i=0; i<6; i++)
957      {
958        mac_byte = m->mac_mask[i];
959        for (; mac_byte; mac_byte >>= 1)
960          mac_bits_set += mac_byte & 1;
961      }
962    /*
963     * Attempt to place the more specific and the more used rules on top.
964     * There are obvious caveat corner cases to this, but they do not
965     * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
966     * going with a wildcard IPv4 with a specific MAC).
967     */
968    return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
969 }
970
971 static int
972 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
973 {
974   /* Ascending sort based on the metric values */
975   return match_type_metric (m1) - match_type_metric (m2);
976 }
977
978 /* Get the offset of L3 source within ethernet packet */
979 static int
980 get_l3_src_offset(int is6)
981 {
982   if(is6)
983     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
984   else
985     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
986 }
987
988 static int
989 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
990 {
991   macip_match_type_t *mvec = NULL;
992   macip_match_type_t *mt;
993   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
994   int i;
995   u32 match_type_index;
996   u32 last_table;
997   u8 mask[5 * 16];
998   vnet_classify_main_t *cm = &vnet_classify_main;
999
1000   /* Count the number of different types of rules */
1001   for (i = 0; i < a->count; i++)
1002     {
1003       if (~0 ==
1004           (match_type_index =
1005            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1006                                   a->rules[i].src_prefixlen,
1007                                   a->rules[i].is_ipv6)))
1008         {
1009           match_type_index = vec_len (mvec);
1010           vec_validate (mvec, match_type_index);
1011           memcpy (mvec[match_type_index].mac_mask,
1012                   a->rules[i].src_mac_mask, 6);
1013           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1014           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1015           mvec[match_type_index].table_index = ~0;
1016         }
1017       mvec[match_type_index].count++;
1018     }
1019   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1020   vec_sort_with_function (mvec, match_type_compare);
1021   /* Create the classifier tables */
1022   last_table = ~0;
1023   /* First add ARP tables */
1024   vec_foreach (mt, mvec)
1025   {
1026     int mask_len;
1027     int is6 = mt->is_ipv6;
1028
1029     mt->arp_table_index = ~0;
1030     if (!is6)
1031       {
1032         memset (mask, 0, sizeof (mask));
1033         memcpy (&mask[6], mt->mac_mask, 6);
1034         memset (&mask[12], 0xff, 2); /* ethernet protocol */
1035         memcpy (&mask[14 + 8], mt->mac_mask, 6);
1036
1037         for (i = 0; i < (mt->prefix_len / 8); i++)
1038           mask[14 + 14 + i] = 0xff;
1039         if (mt->prefix_len % 8)
1040           mask[14 + 14 + (mt->prefix_len / 8)] = 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1041
1042         mask_len = ((14 + 14 + ((mt->prefix_len+7) / 8) +
1043                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1044         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1045                                (~0 == last_table) ? 0 : ~0, &mt->arp_table_index,
1046                                1);
1047         last_table = mt->arp_table_index;
1048       }
1049   }
1050   /* Now add IP[46] tables */
1051   vec_foreach (mt, mvec)
1052   {
1053     int mask_len;
1054     int is6 = mt->is_ipv6;
1055     int l3_src_offs = get_l3_src_offset(is6);
1056     memset (mask, 0, sizeof (mask));
1057     memcpy (&mask[6], mt->mac_mask, 6);
1058     for (i = 0; i < (mt->prefix_len / 8); i++)
1059       {
1060         mask[l3_src_offs + i] = 0xff;
1061       }
1062     if (mt->prefix_len % 8)
1063       {
1064         mask[l3_src_offs + (mt->prefix_len / 8)] =
1065           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1066       }
1067     /*
1068      * Round-up the number of bytes needed to store the prefix,
1069      * and round up the number of vectors too
1070      */
1071     mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) +
1072                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1073     acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1074                                 (~0 == last_table) ? 0 : ~0, &mt->table_index,
1075                                 1);
1076     last_table = mt->table_index;
1077   }
1078   a->ip4_table_index = ~0;
1079   a->ip6_table_index = ~0;
1080   a->l2_table_index = last_table;
1081
1082   /* Populate the classifier tables with rules from the MACIP ACL */
1083   for (i = 0; i < a->count; i++)
1084     {
1085       u32 action = 0;
1086       u32 metadata = 0;
1087       int is6 = a->rules[i].is_ipv6;
1088       int l3_src_offs = get_l3_src_offset(is6);
1089       memset (mask, 0, sizeof (mask));
1090       memcpy (&mask[6], a->rules[i].src_mac, 6);
1091       memset (&mask[12], 0xff, 2); /* ethernet protocol */
1092       if (is6)
1093         {
1094           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1095           mask[12] = 0x86;
1096           mask[13] = 0xdd;
1097         }
1098       else
1099         {
1100           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1101           mask[12] = 0x08;
1102           mask[13] = 0x00;
1103         }
1104       match_type_index =
1105         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1106                                a->rules[i].src_prefixlen,
1107                                a->rules[i].is_ipv6);
1108       ASSERT(match_type_index != ~0);
1109       /* add session to table mvec[match_type_index].table_index; */
1110       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
1111                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
1112                                      0, action, metadata, 1);
1113       /* add ARP table entry too */
1114       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1115         {
1116           memset (mask, 0, sizeof (mask));
1117           memcpy (&mask[6], a->rules[i].src_mac, 6);
1118           mask[12] = 0x08;
1119           mask[13] = 0x06;
1120           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
1121           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
1122           vnet_classify_add_del_session (cm, mvec[match_type_index].arp_table_index,
1123                                     mask, a->rules[i].is_permit ? ~0 : 0, i,
1124                                     0, action, metadata, 1);
1125         }
1126     }
1127   return 0;
1128 }
1129
1130 static void
1131 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1132 {
1133   vnet_classify_main_t *cm = &vnet_classify_main;
1134   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1135
1136   if (a->ip4_table_index != ~0)
1137     {
1138       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
1139       a->ip4_table_index = ~0;
1140     }
1141   if (a->ip6_table_index != ~0)
1142     {
1143       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
1144       a->ip6_table_index = ~0;
1145     }
1146   if (a->l2_table_index != ~0)
1147     {
1148       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
1149       a->l2_table_index = ~0;
1150     }
1151 }
1152
1153 static int
1154 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1155                     u32 * acl_list_index, u8 * tag)
1156 {
1157   acl_main_t *am = &acl_main;
1158   macip_acl_list_t *a;
1159   macip_acl_rule_t *r;
1160   macip_acl_rule_t *acl_new_rules = 0;
1161   int i;
1162
1163   if (*acl_list_index != ~0)
1164     {
1165       /* They supplied some number, let's see if this MACIP ACL exists */
1166       if (pool_is_free_index (am->macip_acls, *acl_list_index))
1167   {
1168     /* tried to replace a non-existent ACL, no point doing anything */
1169           clib_warning("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)", *acl_list_index, tag);
1170     return -1;
1171   }
1172     }
1173
1174   if (0 == count) {
1175     clib_warning("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)", tag);
1176   }
1177   void *oldheap = acl_set_heap(am);
1178   /* Create and populate the rules */
1179   if (count > 0)
1180     vec_validate(acl_new_rules, count-1);
1181
1182   for (i = 0; i < count; i++)
1183     {
1184       r = &acl_new_rules[i];
1185       r->is_permit = rules[i].is_permit;
1186       r->is_ipv6 = rules[i].is_ipv6;
1187       memcpy (&r->src_mac, rules[i].src_mac, 6);
1188       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1189       if(rules[i].is_ipv6)
1190         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1191       else
1192         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1193       r->src_prefixlen = rules[i].src_ip_prefix_len;
1194     }
1195
1196   if (~0 == *acl_list_index)
1197     {
1198       /* Get ACL index */
1199       pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1200       memset (a, 0, sizeof (*a));
1201       /* Will return the newly allocated ACL index */
1202       *acl_list_index = a - am->macip_acls;
1203     }
1204   else
1205     {
1206       a = pool_elt_at_index (am->macip_acls, *acl_list_index);
1207       if (a->rules)
1208         {
1209           vec_free (a->rules);
1210         }
1211       macip_destroy_classify_tables (am, *acl_list_index);
1212     }
1213
1214   a->rules = acl_new_rules;
1215   a->count = count;
1216   memcpy (a->tag, tag, sizeof (a->tag));
1217
1218   /* Create and populate the classifer tables */
1219   macip_create_classify_tables (am, *acl_list_index);
1220   clib_mem_set_heap (oldheap);
1221   return 0;
1222 }
1223
1224
1225 /* No check for validity of sw_if_index - the callers were supposed to validate */
1226
1227 static int
1228 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1229 {
1230   int rv;
1231   u32 macip_acl_index;
1232   macip_acl_list_t *a;
1233   void *oldheap = acl_set_heap(am);
1234   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1235   clib_mem_set_heap (oldheap);
1236   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1237   /* No point in deleting MACIP ACL which is not applied */
1238   if (~0 == macip_acl_index)
1239     return -1;
1240   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1241   /* remove the classifier tables off the interface L2 ACL */
1242   rv =
1243     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1244                               a->ip6_table_index, a->l2_table_index, 0);
1245   /* Unset the MACIP ACL index */
1246   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1247   return rv;
1248 }
1249
1250 /* No check for validity of sw_if_index - the callers were supposed to validate */
1251
1252 static int
1253 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1254                              u32 macip_acl_index)
1255 {
1256   macip_acl_list_t *a;
1257   int rv;
1258   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1259     {
1260       return -1;
1261     }
1262   void *oldheap = acl_set_heap(am);
1263   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1264   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1265   /* If there already a MACIP ACL applied, unapply it */
1266   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1267     macip_acl_interface_del_acl(am, sw_if_index);
1268   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1269   clib_mem_set_heap (oldheap);
1270
1271   /* Apply the classifier tables for L2 ACLs */
1272   rv =
1273     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1274                               a->ip6_table_index, a->l2_table_index, 1);
1275   return rv;
1276 }
1277
1278 static int
1279 macip_acl_del_list (u32 acl_list_index)
1280 {
1281   acl_main_t *am = &acl_main;
1282   void *oldheap = acl_set_heap(am);
1283   macip_acl_list_t *a;
1284   int i;
1285   if (pool_is_free_index (am->macip_acls, acl_list_index))
1286     {
1287       return -1;
1288     }
1289
1290   /* delete any references to the ACL */
1291   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1292     {
1293       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1294         {
1295           macip_acl_interface_del_acl (am, i);
1296         }
1297     }
1298
1299   /* Now that classifier tables are detached, clean them up */
1300   macip_destroy_classify_tables (am, acl_list_index);
1301
1302   /* now we can delete the ACL itself */
1303   a = pool_elt_at_index (am->macip_acls, acl_list_index);
1304   if (a->rules)
1305     {
1306       vec_free (a->rules);
1307     }
1308   pool_put (am->macip_acls, a);
1309   clib_mem_set_heap (oldheap);
1310   return 0;
1311 }
1312
1313
1314 static int
1315 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1316                                  u32 acl_list_index)
1317 {
1318   acl_main_t *am = &acl_main;
1319   void *oldheap = acl_set_heap(am);
1320   int rv = -1;
1321   if (is_add)
1322     {
1323       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1324     }
1325   else
1326     {
1327       rv = macip_acl_interface_del_acl (am, sw_if_index);
1328     }
1329   clib_mem_set_heap (oldheap);
1330   return rv;
1331 }
1332
1333 /*
1334  * If the client does not allocate enough memory for a variable-length
1335  * message, and then proceed to use it as if the full memory allocated,
1336  * absent the check we happily consume that on the VPP side, and go
1337  * along as if nothing happened. However, the resulting
1338  * effects range from just garbage in the API decode
1339  * (because the decoder snoops too far), to potential memory
1340  * corruptions.
1341  *
1342  * This verifies that the actual length of the message is
1343  * at least expected_len, and complains loudly if it is not.
1344  *
1345  * A failing check here is 100% a software bug on the API user side,
1346  * so we might as well yell.
1347  *
1348  */
1349 static int verify_message_len(void *mp, u32 expected_len, char *where)
1350 {
1351   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1352   if (supplied_len < expected_len) {
1353       clib_warning("%s: Supplied message length %d is less than expected %d",
1354                    where, supplied_len, expected_len);
1355       return 0;
1356   } else {
1357       return 1;
1358   }
1359 }
1360
1361 /* API message handler */
1362 static void
1363 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1364 {
1365   vl_api_acl_add_replace_reply_t *rmp;
1366   acl_main_t *am = &acl_main;
1367   int rv;
1368   u32 acl_list_index = ntohl (mp->acl_index);
1369   u32 acl_count = ntohl (mp->count);
1370   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1371
1372   if (verify_message_len(mp, expected_len, "acl_add_replace")) {
1373       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1374   } else {
1375       rv = VNET_API_ERROR_INVALID_VALUE;
1376   }
1377
1378   /* *INDENT-OFF* */
1379   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1380   ({
1381     rmp->acl_index = htonl(acl_list_index);
1382   }));
1383   /* *INDENT-ON* */
1384 }
1385
1386 static void
1387 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1388 {
1389   acl_main_t *am = &acl_main;
1390   vl_api_acl_del_reply_t *rmp;
1391   int rv;
1392
1393   rv = acl_del_list (ntohl (mp->acl_index));
1394
1395   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1396 }
1397
1398 static void
1399 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1400 {
1401   acl_main_t *am = &acl_main;
1402   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1403   u32 sw_if_index = ntohl (mp->sw_if_index);
1404   vl_api_acl_interface_add_del_reply_t *rmp;
1405   int rv = -1;
1406
1407   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1408     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1409   else
1410     rv =
1411       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1412                                      mp->is_input, ntohl (mp->acl_index));
1413
1414   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1415 }
1416
1417 static void
1418 vl_api_acl_interface_set_acl_list_t_handler
1419   (vl_api_acl_interface_set_acl_list_t * mp)
1420 {
1421   acl_main_t *am = &acl_main;
1422   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1423   int rv = 0;
1424   int i;
1425   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1426   u32 sw_if_index = ntohl (mp->sw_if_index);
1427
1428   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1429     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1430   else
1431     {
1432       acl_interface_reset_inout_acls (sw_if_index, 0);
1433       acl_interface_reset_inout_acls (sw_if_index, 1);
1434
1435       for (i = 0; i < mp->count; i++)
1436         {
1437           if(acl_is_not_defined(am, ntohl (mp->acls[i]))) {
1438             /* ACL does not exist, so we can not apply it */
1439             rv = -1;
1440           }
1441         }
1442       if (0 == rv) {
1443         for (i = 0; i < mp->count; i++)
1444           {
1445             acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1446                                        ntohl (mp->acls[i]));
1447           }
1448       }
1449     }
1450
1451   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1452 }
1453
1454 static void
1455 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1456 {
1457   api_rule->is_permit = r->is_permit;
1458   api_rule->is_ipv6 = r->is_ipv6;
1459   if(r->is_ipv6)
1460     {
1461       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1462       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1463     }
1464   else
1465     {
1466       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1467       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1468     }
1469   api_rule->src_ip_prefix_len = r->src_prefixlen;
1470   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1471   api_rule->proto = r->proto;
1472   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1473   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1474   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1475   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1476   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1477   api_rule->tcp_flags_value = r->tcp_flags_value;
1478 }
1479
1480 static void
1481 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1482                   acl_list_t * acl, u32 context)
1483 {
1484   vl_api_acl_details_t *mp;
1485   vl_api_acl_rule_t *rules;
1486   int i;
1487   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1488   void *oldheap = acl_set_heap(am);
1489
1490   mp = vl_msg_api_alloc (msg_size);
1491   memset (mp, 0, msg_size);
1492   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1493
1494   /* fill in the message */
1495   mp->context = context;
1496   mp->count = htonl (acl->count);
1497   mp->acl_index = htonl (acl - am->acls);
1498   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1499   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1500   rules = mp->r;
1501   for (i = 0; i < acl->count; i++)
1502     {
1503       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1504     }
1505
1506   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1507   clib_mem_set_heap (oldheap);
1508   vl_msg_api_send_shmem (q, (u8 *) & mp);
1509 }
1510
1511
1512 static void
1513 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1514 {
1515   acl_main_t *am = &acl_main;
1516   u32 acl_index;
1517   acl_list_t *acl;
1518
1519   int rv = -1;
1520   unix_shared_memory_queue_t *q;
1521
1522   q = vl_api_client_index_to_input_queue (mp->client_index);
1523   if (q == 0)
1524     {
1525       return;
1526     }
1527
1528   if (mp->acl_index == ~0)
1529     {
1530     /* *INDENT-OFF* */
1531     /* Just dump all ACLs */
1532     pool_foreach (acl, am->acls,
1533     ({
1534       send_acl_details(am, q, acl, mp->context);
1535     }));
1536     /* *INDENT-ON* */
1537     }
1538   else
1539     {
1540       acl_index = ntohl (mp->acl_index);
1541       if (!pool_is_free_index (am->acls, acl_index))
1542        {
1543          acl = pool_elt_at_index (am->acls, acl_index);
1544          send_acl_details (am, q, acl, mp->context);
1545        }
1546     }
1547
1548   if (rv == -1)
1549     {
1550       /* FIXME API: should we signal an error here at all ? */
1551       return;
1552     }
1553 }
1554
1555 static void
1556 send_acl_interface_list_details (acl_main_t * am,
1557                                  unix_shared_memory_queue_t * q,
1558                                  u32 sw_if_index, u32 context)
1559 {
1560   vl_api_acl_interface_list_details_t *mp;
1561   int msg_size;
1562   int n_input;
1563   int n_output;
1564   int count;
1565   int i = 0;
1566   void *oldheap = acl_set_heap(am);
1567
1568   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1569   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1570
1571   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1572   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1573   count = n_input + n_output;
1574
1575   msg_size = sizeof (*mp);
1576   msg_size += sizeof (mp->acls[0]) * count;
1577
1578   mp = vl_msg_api_alloc (msg_size);
1579   memset (mp, 0, msg_size);
1580   mp->_vl_msg_id =
1581     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1582
1583   /* fill in the message */
1584   mp->context = context;
1585   mp->sw_if_index = htonl (sw_if_index);
1586   mp->count = count;
1587   mp->n_input = n_input;
1588   for (i = 0; i < n_input; i++)
1589     {
1590       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1591     }
1592   for (i = 0; i < n_output; i++)
1593     {
1594       mp->acls[n_input + i] =
1595         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1596     }
1597   clib_mem_set_heap (oldheap);
1598   vl_msg_api_send_shmem (q, (u8 *) & mp);
1599 }
1600
1601 static void
1602 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1603                                           mp)
1604 {
1605   acl_main_t *am = &acl_main;
1606   vnet_sw_interface_t *swif;
1607   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1608
1609   u32 sw_if_index;
1610   unix_shared_memory_queue_t *q;
1611
1612   q = vl_api_client_index_to_input_queue (mp->client_index);
1613   if (q == 0)
1614     {
1615       return;
1616     }
1617
1618   if (mp->sw_if_index == ~0)
1619     {
1620     /* *INDENT-OFF* */
1621     pool_foreach (swif, im->sw_interfaces,
1622     ({
1623       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1624     }));
1625     /* *INDENT-ON* */
1626     }
1627   else
1628     {
1629       sw_if_index = ntohl (mp->sw_if_index);
1630       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1631         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1632     }
1633 }
1634
1635 /* MACIP ACL API handlers */
1636
1637 static void
1638 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1639 {
1640   vl_api_macip_acl_add_reply_t *rmp;
1641   acl_main_t *am = &acl_main;
1642   int rv;
1643   u32 acl_list_index = ~0;
1644   u32 acl_count = ntohl (mp->count);
1645   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1646
1647   if (verify_message_len(mp, expected_len, "macip_acl_add")) {
1648       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1649   } else {
1650       rv = VNET_API_ERROR_INVALID_VALUE;
1651   }
1652
1653   /* *INDENT-OFF* */
1654   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1655   ({
1656     rmp->acl_index = htonl(acl_list_index);
1657   }));
1658   /* *INDENT-ON* */
1659 }
1660
1661 static void
1662 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
1663 {
1664   vl_api_macip_acl_add_replace_reply_t *rmp;
1665   acl_main_t *am = &acl_main;
1666   int rv;
1667   u32 acl_list_index = ntohl (mp->acl_index);
1668   u32 acl_count = ntohl (mp->count);
1669   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1670
1671   if (verify_message_len(mp, expected_len, "macip_acl_add_replace")) {
1672       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1673   } else {
1674       rv = VNET_API_ERROR_INVALID_VALUE;
1675   }
1676
1677   /* *INDENT-OFF* */
1678   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
1679   ({
1680     rmp->acl_index = htonl(acl_list_index);
1681   }));
1682   /* *INDENT-ON* */
1683 }
1684
1685 static void
1686 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1687 {
1688   acl_main_t *am = &acl_main;
1689   vl_api_macip_acl_del_reply_t *rmp;
1690   int rv;
1691
1692   rv = macip_acl_del_list (ntohl (mp->acl_index));
1693
1694   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1695 }
1696
1697 static void
1698 vl_api_macip_acl_interface_add_del_t_handler
1699   (vl_api_macip_acl_interface_add_del_t * mp)
1700 {
1701   acl_main_t *am = &acl_main;
1702   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1703   int rv = -1;
1704   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1705   u32 sw_if_index = ntohl (mp->sw_if_index);
1706
1707   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1708     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1709   else
1710     rv =
1711       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1712                                      ntohl (mp->acl_index));
1713
1714   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1715 }
1716
1717 static void
1718 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1719                         macip_acl_list_t * acl, u32 context)
1720 {
1721   vl_api_macip_acl_details_t *mp;
1722   vl_api_macip_acl_rule_t *rules;
1723   macip_acl_rule_t *r;
1724   int i;
1725   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1726
1727   mp = vl_msg_api_alloc (msg_size);
1728   memset (mp, 0, msg_size);
1729   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1730
1731   /* fill in the message */
1732   mp->context = context;
1733   if (acl)
1734     {
1735       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1736       mp->count = htonl (acl->count);
1737       mp->acl_index = htonl (acl - am->macip_acls);
1738       rules = mp->r;
1739       for (i = 0; i < acl->count; i++)
1740         {
1741           r = &acl->rules[i];
1742           rules[i].is_permit = r->is_permit;
1743           rules[i].is_ipv6 = r->is_ipv6;
1744           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1745           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1746                   sizeof (r->src_mac_mask));
1747           if (r->is_ipv6)
1748             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1749                   sizeof (r->src_ip_addr.ip6));
1750           else
1751             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1752                   sizeof (r->src_ip_addr.ip4));
1753           rules[i].src_ip_prefix_len = r->src_prefixlen;
1754         }
1755     }
1756   else
1757     {
1758       /* No martini, no party - no ACL applied to this interface. */
1759       mp->acl_index = ~0;
1760       mp->count = 0;
1761     }
1762
1763   vl_msg_api_send_shmem (q, (u8 *) & mp);
1764 }
1765
1766
1767 static void
1768 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1769 {
1770   acl_main_t *am = &acl_main;
1771   macip_acl_list_t *acl;
1772
1773   unix_shared_memory_queue_t *q;
1774
1775   q = vl_api_client_index_to_input_queue (mp->client_index);
1776   if (q == 0)
1777     {
1778       return;
1779     }
1780
1781   if (mp->acl_index == ~0)
1782     {
1783       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1784       pool_foreach (acl, am->macip_acls, (
1785                                            {
1786                                            send_macip_acl_details (am, q, acl,
1787                                                                    mp->
1788                                                                    context);}
1789                     ));
1790       /* *INDENT-ON* */
1791     }
1792   else
1793     {
1794       u32 acl_index = ntohl (mp->acl_index);
1795       if (!pool_is_free_index (am->macip_acls, acl_index))
1796        {
1797          acl = pool_elt_at_index (am->macip_acls, acl_index);
1798          send_macip_acl_details (am, q, acl, mp->context);
1799        }
1800     }
1801 }
1802
1803 static void
1804 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1805                                           mp)
1806 {
1807   acl_main_t *am = &acl_main;
1808   vl_api_macip_acl_interface_get_reply_t *rmp;
1809   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1810   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1811   unix_shared_memory_queue_t *q;
1812   int i;
1813
1814   q = vl_api_client_index_to_input_queue (mp->client_index);
1815   if (q == 0)
1816     {
1817       return;
1818     }
1819
1820   rmp = vl_msg_api_alloc (msg_size);
1821   memset (rmp, 0, msg_size);
1822   rmp->_vl_msg_id =
1823     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1824   rmp->context = mp->context;
1825   rmp->count = htonl (count);
1826   for (i = 0; i < count; i++)
1827     {
1828       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1829     }
1830
1831   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1832 }
1833
1834 static void
1835 send_macip_acl_interface_list_details (acl_main_t * am,
1836                                        unix_shared_memory_queue_t * q,
1837                                        u32 sw_if_index,
1838                                        u32 acl_index,
1839                                        u32 context)
1840 {
1841   vl_api_macip_acl_interface_list_details_t *rmp;
1842   /* at this time there is only ever 1 mac ip acl per interface */
1843   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
1844
1845   rmp = vl_msg_api_alloc (msg_size);
1846   memset (rmp, 0, msg_size);
1847   rmp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1848
1849   /* fill in the message */
1850   rmp->context = context;
1851   rmp->count = 1;
1852   rmp->sw_if_index = htonl (sw_if_index);
1853   rmp->acls[0] = htonl (acl_index);
1854
1855   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1856 }
1857
1858 static void
1859 vl_api_macip_acl_interface_list_dump_t_handler (vl_api_macip_acl_interface_list_dump_t *mp)
1860 {
1861   unix_shared_memory_queue_t *q;
1862   acl_main_t *am = &acl_main;
1863   u32 sw_if_index = ntohl (mp->sw_if_index);
1864
1865   q = vl_api_client_index_to_input_queue (mp->client_index);
1866   if (q == 0)
1867     {
1868       return;
1869     }
1870
1871   if (sw_if_index == ~0)
1872     {
1873       vec_foreach_index(sw_if_index, am->macip_acl_by_sw_if_index)
1874         {
1875           if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1876             {
1877               send_macip_acl_interface_list_details(am, q,  sw_if_index,
1878                                                     am->macip_acl_by_sw_if_index[sw_if_index],
1879                                                     mp->context);
1880             }
1881         }
1882     }
1883   else
1884     {
1885       if (vec_len(am->macip_acl_by_sw_if_index) > sw_if_index)
1886         {
1887           send_macip_acl_interface_list_details(am, q, sw_if_index,
1888                                                 am->macip_acl_by_sw_if_index[sw_if_index],
1889                                                 mp->context);
1890         }
1891     }
1892 }
1893
1894 /* Set up the API message handling tables */
1895 static clib_error_t *
1896 acl_plugin_api_hookup (vlib_main_t * vm)
1897 {
1898   acl_main_t *am = &acl_main;
1899 #define _(N,n)                                                  \
1900     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
1901                            #n,                                  \
1902                            vl_api_##n##_t_handler,              \
1903                            vl_noop_handler,                     \
1904                            vl_api_##n##_t_endian,               \
1905                            vl_api_##n##_t_print,                \
1906                            sizeof(vl_api_##n##_t), 1);
1907   foreach_acl_plugin_api_msg;
1908 #undef _
1909
1910   return 0;
1911 }
1912
1913 #define vl_msg_name_crc_list
1914 #include <acl/acl_all_api_h.h>
1915 #undef vl_msg_name_crc_list
1916
1917 static void
1918 setup_message_id_table (acl_main_t * am, api_main_t * apim)
1919 {
1920 #define _(id,n,crc) \
1921   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
1922   foreach_vl_msg_name_crc_acl;
1923 #undef _
1924 }
1925
1926 static void
1927 acl_setup_fa_nodes (void)
1928 {
1929   vlib_main_t *vm = vlib_get_main ();
1930   acl_main_t *am = &acl_main;
1931   vlib_node_t *n, *n4, *n6;
1932
1933   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1934   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
1935   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
1936
1937
1938   am->l2_input_classify_next_acl_ip4 =
1939     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1940   am->l2_input_classify_next_acl_ip6 =
1941     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1942
1943   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
1944                                l2input_get_feat_names (),
1945                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
1946
1947   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
1948                                l2input_get_feat_names (),
1949                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
1950
1951
1952   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1953   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
1954   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
1955
1956   am->l2_output_classify_next_acl_ip4 =
1957     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1958   am->l2_output_classify_next_acl_ip6 =
1959     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1960
1961   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
1962                                l2output_get_feat_names (),
1963                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
1964
1965   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
1966                                l2output_get_feat_names (),
1967                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
1968 }
1969
1970 static void
1971 acl_set_timeout_sec(int timeout_type, u32 value)
1972 {
1973   acl_main_t *am = &acl_main;
1974   clib_time_t *ct = &am->vlib_main->clib_time;
1975
1976   if (timeout_type < ACL_N_TIMEOUTS) {
1977     am->session_timeout_sec[timeout_type] = value;
1978   } else {
1979     clib_warning("Unknown timeout type %d", timeout_type);
1980     return;
1981   }
1982   am->session_timeout[timeout_type] = (u64)(((f64)value)/ct->seconds_per_clock);
1983 }
1984
1985 static void
1986 acl_set_session_max_entries(u32 value)
1987 {
1988   acl_main_t *am = &acl_main;
1989   am->fa_conn_table_max_entries = value;
1990 }
1991
1992 static int
1993 acl_set_skip_ipv6_eh(u32 eh, u32 value)
1994 {
1995   acl_main_t *am = &acl_main;
1996
1997   if ((eh < 256) && (value < 2))
1998     {
1999       am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, eh, value);
2000       return 1;
2001     }
2002   else
2003     return 0;
2004 }
2005
2006
2007 static clib_error_t *
2008 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
2009 {
2010   acl_main_t *am = &acl_main;
2011   if (0 == am->acl_mheap) {
2012     /* ACL heap is not initialized, so definitely nothing to do. */
2013     return 0;
2014   }
2015   if (0 == is_add) {
2016     vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2017                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, sw_if_index);
2018     /* also unapply any ACLs in case the users did not do so. */
2019     macip_acl_interface_del_acl(am, sw_if_index);
2020     acl_interface_reset_inout_acls (sw_if_index, 0);
2021     acl_interface_reset_inout_acls (sw_if_index, 1);
2022   }
2023   return 0;
2024 }
2025
2026 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
2027
2028
2029
2030 static clib_error_t *
2031 acl_set_aclplugin_fn (vlib_main_t * vm,
2032                               unformat_input_t * input,
2033                               vlib_cli_command_t * cmd)
2034 {
2035   clib_error_t *error = 0;
2036   u32 timeout = 0;
2037   u32 val = 0;
2038   u32 eh_val = 0;
2039   uword memory_size = 0;
2040   acl_main_t *am = &acl_main;
2041
2042   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val)) {
2043     if(!acl_set_skip_ipv6_eh(eh_val, val)) {
2044       error = clib_error_return(0, "expecting eh=0..255, value=0..1");
2045     }
2046     goto done;
2047   }
2048   if (unformat (input, "use-hash-acl-matching %u", &val))
2049     {
2050       am->use_hash_acl_matching = (val !=0);
2051       goto done;
2052     }
2053   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
2054     {
2055       am->l4_match_nonfirst_fragment = (val != 0);
2056       goto done;
2057     }
2058   if (unformat (input, "heap"))
2059     {
2060       if (unformat(input, "main"))
2061         {
2062           if (unformat(input, "validate %u", &val))
2063             acl_plugin_acl_set_validate_heap(am, val);
2064           else if (unformat(input, "trace %u", &val))
2065             acl_plugin_acl_set_trace_heap(am, val);
2066           goto done;
2067         }
2068       else if (unformat(input, "hash"))
2069         {
2070           if (unformat(input, "validate %u", &val))
2071             acl_plugin_hash_acl_set_validate_heap(am, val);
2072           else if (unformat(input, "trace %u", &val))
2073             acl_plugin_hash_acl_set_trace_heap(am, val);
2074           goto done;
2075         }
2076       goto done;
2077     }
2078   if (unformat (input, "session")) {
2079     if (unformat (input, "table")) {
2080       /* The commands here are for tuning/testing. No user-serviceable parts inside */
2081       if (unformat (input, "max-entries")) {
2082         if (!unformat(input, "%u", &val)) {
2083           error = clib_error_return(0,
2084                                     "expecting maximum number of entries, got `%U`",
2085                                     format_unformat_error, input);
2086           goto done;
2087         } else {
2088           acl_set_session_max_entries(val);
2089           goto done;
2090         }
2091       }
2092       if (unformat (input, "hash-table-buckets")) {
2093         if (!unformat(input, "%u", &val)) {
2094           error = clib_error_return(0,
2095                                     "expecting maximum number of hash table buckets, got `%U`",
2096                                     format_unformat_error, input);
2097           goto done;
2098         } else {
2099           am->fa_conn_table_hash_num_buckets = val;
2100           goto done;
2101         }
2102       }
2103       if (unformat (input, "hash-table-memory")) {
2104         if (!unformat(input, "%U", unformat_memory_size, &memory_size)) {
2105           error = clib_error_return(0,
2106                                     "expecting maximum amount of hash table memory, got `%U`",
2107                                     format_unformat_error, input);
2108           goto done;
2109         } else {
2110           am->fa_conn_table_hash_memory_size = memory_size;
2111           goto done;
2112         }
2113       }
2114       goto done;
2115     }
2116     if (unformat (input, "timeout")) {
2117       if (unformat(input, "udp")) {
2118         if(unformat(input, "idle")) {
2119           if (!unformat(input, "%u", &timeout)) {
2120             error = clib_error_return(0,
2121                                       "expecting timeout value in seconds, got `%U`",
2122                                       format_unformat_error, input);
2123             goto done;
2124           } else {
2125             acl_set_timeout_sec(ACL_TIMEOUT_UDP_IDLE, timeout);
2126             goto done;
2127           }
2128         }
2129       }
2130       if (unformat(input, "tcp")) {
2131         if(unformat(input, "idle")) {
2132           if (!unformat(input, "%u", &timeout)) {
2133             error = clib_error_return(0,
2134                                       "expecting timeout value in seconds, got `%U`",
2135                                       format_unformat_error, input);
2136             goto done;
2137           } else {
2138             acl_set_timeout_sec(ACL_TIMEOUT_TCP_IDLE, timeout);
2139             goto done;
2140           }
2141         }
2142         if(unformat(input, "transient")) {
2143           if (!unformat(input, "%u", &timeout)) {
2144             error = clib_error_return(0,
2145                                       "expecting timeout value in seconds, got `%U`",
2146                                       format_unformat_error, input);
2147             goto done;
2148           } else {
2149             acl_set_timeout_sec(ACL_TIMEOUT_TCP_TRANSIENT, timeout);
2150             goto done;
2151           }
2152         }
2153       }
2154       goto done;
2155     }
2156   }
2157 done:
2158   return error;
2159 }
2160
2161 static u8 *
2162 my_format_mac_address (u8 * s, va_list * args)
2163 {
2164   u8 *a = va_arg (*args, u8 *);
2165   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
2166                  a[0], a[1], a[2], a[3], a[4], a[5]);
2167 }
2168
2169 static inline u8 *
2170 my_macip_acl_rule_t_pretty_format (u8 *out, va_list *args)
2171 {
2172   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
2173
2174   out = format(out, "%s action %d ip %U/%d mac %U mask %U",
2175                      a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
2176                      format_ip46_address, &a->src_ip_addr, IP46_TYPE_ANY,
2177                      a->src_prefixlen,
2178                      my_format_mac_address, a->src_mac,
2179                      my_format_mac_address, a->src_mac_mask);
2180   return(out);
2181 }
2182
2183 static void
2184 macip_acl_print(acl_main_t *am, u32 macip_acl_index)
2185 {
2186   vlib_main_t * vm = am->vlib_main;
2187   int i;
2188
2189   /* Don't try to print someone else's memory */
2190   if (macip_acl_index > vec_len(am->macip_acls))
2191     return;
2192
2193   macip_acl_list_t *a = vec_elt_at_index(am->macip_acls, macip_acl_index);
2194   int free_pool_slot = pool_is_free_index(am->macip_acls, macip_acl_index);
2195
2196   vlib_cli_output(vm, "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
2197                   macip_acl_index, a->count, vec_len(a->rules), a->tag, free_pool_slot);
2198   vlib_cli_output(vm, "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
2199                   a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
2200   for(i=0; i<vec_len(a->rules); i++)
2201     vlib_cli_output(vm, "    rule %d: %U\n", i, my_macip_acl_rule_t_pretty_format,
2202                     vec_elt_at_index(a->rules, i));
2203
2204 }
2205
2206 static clib_error_t *
2207 acl_show_aclplugin_macip_fn (vlib_main_t * vm,
2208                               unformat_input_t * input,
2209                               vlib_cli_command_t * cmd)
2210 {
2211   clib_error_t *error = 0;
2212   acl_main_t *am = &acl_main;
2213   int i;
2214   if (unformat (input, "interface"))
2215     {
2216       for(i=0; i < vec_len(am->macip_acl_by_sw_if_index); i++)
2217         {
2218           vlib_cli_output(vm, "  sw_if_index %d: %d\n", i, vec_elt(am->macip_acl_by_sw_if_index, i));
2219         }
2220     }
2221   else if (unformat (input, "acl"))
2222     {
2223       for(i=0; i < vec_len(am->macip_acls); i++)
2224         macip_acl_print(am, i);
2225     }
2226   return error;
2227 }
2228
2229
2230 static clib_error_t *
2231 acl_show_aclplugin_fn (vlib_main_t * vm,
2232                               unformat_input_t * input,
2233                               vlib_cli_command_t * cmd)
2234 {
2235   clib_error_t *error = 0;
2236   acl_main_t *am = &acl_main;
2237   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2238   u32 *pj;
2239
2240   vnet_sw_interface_t *swif;
2241
2242   if (unformat (input, "sessions"))
2243     {
2244       u8 * out0 = format(0, "");
2245       u16 wk;
2246       u32 show_bihash_verbose = 0;
2247       u32 show_session_thread_id = ~0;
2248       u32 show_session_session_index = ~0;
2249       unformat (input, "thread %u index %u", &show_session_thread_id, &show_session_session_index);
2250       unformat (input, "verbose %u", &show_bihash_verbose);
2251       {
2252         u64 n_adds = am->fa_session_total_adds;
2253         u64 n_dels = am->fa_session_total_dels;
2254         out0 = format(out0, "Sessions total: add %lu - del %lu = %lu\n", n_adds, n_dels, n_adds - n_dels);
2255       }
2256       out0 = format(out0, "\n\nPer-thread data:\n");
2257       for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2258         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2259         out0 = format(out0, "Thread #%d:\n", wk);
2260         if (show_session_thread_id == wk && show_session_session_index < pool_len(pw->fa_sessions_pool)) {
2261           out0 = format(out0, "  session index %u:\n", show_session_session_index);
2262           fa_session_t *sess = pw->fa_sessions_pool + show_session_session_index;
2263           u64 *m =  (u64 *)&sess->info;
2264           out0 = format(out0, "    info: %016llx %016llx %016llx %016llx %016llx %016llx\n", m[0], m[1], m[2], m[3], m[4], m[5]);
2265           out0 = format(out0, "    sw_if_index: %u\n", sess->sw_if_index);
2266           out0 = format(out0, "    tcp_flags_seen: %x\n", sess->tcp_flags_seen.as_u16);
2267           out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2268           out0 = format(out0, "    thread index: %u\n", sess->thread_index);
2269           out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2270           out0 = format(out0, "    link next index: %u\n", sess->link_next_idx);
2271           out0 = format(out0, "    link prev index: %u\n", sess->link_prev_idx);
2272           out0 = format(out0, "    link list id: %u\n", sess->link_list_id);
2273         }
2274         out0 = format(out0, "  connection add/del stats:\n", wk);
2275         pool_foreach (swif, im->sw_interfaces,
2276         ({
2277           u32 sw_if_index =  swif->sw_if_index;
2278           u64 n_adds = sw_if_index < vec_len(pw->fa_session_adds_by_sw_if_index) ? pw->fa_session_adds_by_sw_if_index[sw_if_index] : 0;
2279           u64 n_dels = sw_if_index < vec_len(pw->fa_session_dels_by_sw_if_index) ? pw->fa_session_dels_by_sw_if_index[sw_if_index] : 0;
2280           out0 = format(out0, "    sw_if_index %d: add %lu - del %lu = %lu\n", sw_if_index, n_adds, n_dels, n_adds - n_dels);
2281         }));
2282
2283         out0 = format(out0, "  connection timeout type lists:\n", wk);
2284         u8 tt = 0;
2285         for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2286           u32 head_session_index = pw->fa_conn_list_head[tt];
2287           out0 = format(out0, "  fa_conn_list_head[%d]: %d\n", tt, head_session_index);
2288           if (~0 != head_session_index) {
2289             fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
2290             out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2291             out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2292           }
2293         }
2294
2295         out0 = format(out0, "  Next expiry time: %lu\n", pw->next_expiry_time);
2296         out0 = format(out0, "  Requeue until time: %lu\n", pw->requeue_until_time);
2297         out0 = format(out0, "  Current time wait interval: %lu\n", pw->current_time_wait_interval);
2298         out0 = format(out0, "  Count of deleted sessions: %lu\n", pw->cnt_deleted_sessions);
2299         out0 = format(out0, "  Delete already deleted: %lu\n", pw->cnt_already_deleted_sessions);
2300         out0 = format(out0, "  Session timers restarted: %lu\n", pw->cnt_session_timer_restarted);
2301         out0 = format(out0, "  Swipe until this time: %lu\n", pw->swipe_end_time);
2302         out0 = format(out0, "  sw_if_index serviced bitmap: %U\n", format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
2303         out0 = format(out0, "  pending clear intfc bitmap : %U\n", format_bitmap_hex, pw->pending_clear_sw_if_index_bitmap);
2304         out0 = format(out0, "  clear in progress: %u\n", pw->clear_in_process);
2305         out0 = format(out0, "  interrupt is pending: %d\n", pw->interrupt_is_pending);
2306         out0 = format(out0, "  interrupt is needed: %d\n", pw->interrupt_is_needed);
2307         out0 = format(out0, "  interrupt is unwanted: %d\n", pw->interrupt_is_unwanted);
2308         out0 = format(out0, "  interrupt generation: %d\n", pw->interrupt_generation);
2309       }
2310       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
2311 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
2312       foreach_fa_cleaner_counter;
2313 #undef _
2314       vec_terminate_c_string(out0);
2315       vlib_cli_output(vm, "\n\n%s\n\n", out0);
2316       vlib_cli_output(vm, "Interrupt generation: %d\n", am->fa_interrupt_generation);
2317       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
2318               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
2319               am->fa_cleaner_wait_time_increment * 1000.0, ((f64)am->fa_current_cleaner_timer_wait_interval) * 1000.0/(f64)vm->clib_time.clocks_per_second);
2320
2321       vec_free(out0);
2322       show_fa_sessions_hash(vm, show_bihash_verbose);
2323     }
2324   else if (unformat (input, "interface"))
2325     {
2326       u32 sw_if_index = ~0;
2327       u32 swi;
2328       u8 * out0 = format(0, "");
2329       unformat (input, "sw_if_index %u", &sw_if_index);
2330       for(swi = 0; (swi < vec_len(am->input_acl_vec_by_sw_if_index)) ||
2331                    (swi < vec_len(am->output_acl_vec_by_sw_if_index)); swi++) {
2332         out0 = format(out0, "sw_if_index %d:\n", swi);
2333
2334         if ((swi < vec_len(am->input_acl_vec_by_sw_if_index)) &&
2335             (vec_len(am->input_acl_vec_by_sw_if_index[swi]) > 0)) {
2336           out0 = format(out0, "  input acl(s): ");
2337           vec_foreach(pj, am->input_acl_vec_by_sw_if_index[swi]) {
2338             out0 = format(out0, "%d ", *pj);
2339           }
2340           out0 = format(out0, "\n");
2341         }
2342
2343         if ((swi < vec_len(am->output_acl_vec_by_sw_if_index)) &&
2344             (vec_len(am->output_acl_vec_by_sw_if_index[swi]) > 0)) {
2345           out0 = format(out0, "  output acl(s): ");
2346           vec_foreach(pj, am->output_acl_vec_by_sw_if_index[swi]) {
2347             out0 = format(out0, "%d ", *pj);
2348           }
2349           out0 = format(out0, "\n");
2350         }
2351
2352       }
2353       vec_terminate_c_string(out0);
2354       vlib_cli_output(vm, "\n%s\n", out0);
2355       vec_free(out0);
2356     }
2357   else if (unformat (input, "acl"))
2358     {
2359       u32 acl_index = ~0;
2360       u32 i;
2361       u8 * out0 = format(0, "");
2362       unformat (input, "index %u", &acl_index);
2363       for(i=0; i<vec_len(am->acls); i++) {
2364         if (acl_is_not_defined(am, i)) {
2365           /* don't attempt to show the ACLs that do not exist */
2366           continue;
2367         }
2368         if ((acl_index != ~0) && (acl_index != i)) {
2369           continue;
2370         }
2371         out0 = format(out0, "acl-index %u count %u tag {%s}\n", i, am->acls[i].count, am->acls[i].tag);
2372         acl_rule_t *r;
2373         int j;
2374         for(j=0; j<am->acls[i].count; j++) {
2375           r = &am->acls[i].rules[j];
2376           out0 = format(out0, "  %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
2377           out0 = format_acl_action(out0, r->is_permit);
2378           out0 = format(out0, " src %U/%d", format_ip46_address, &r->src, IP46_TYPE_ANY, r->src_prefixlen);
2379           out0 = format(out0, " dst %U/%d", format_ip46_address, &r->dst, IP46_TYPE_ANY, r->dst_prefixlen);
2380           out0 = format(out0, " proto %d", r->proto);
2381           out0 = format(out0, " sport %d", r->src_port_or_type_first);
2382           if (r->src_port_or_type_first != r->src_port_or_type_last) {
2383             out0 = format(out0, "-%d", r->src_port_or_type_last);
2384           }
2385           out0 = format(out0, " dport %d", r->dst_port_or_code_first);
2386           if (r->dst_port_or_code_first != r->dst_port_or_code_last) {
2387             out0 = format(out0, "-%d", r->dst_port_or_code_last);
2388           }
2389           if (r->tcp_flags_mask || r->tcp_flags_value) {
2390             out0 = format(out0, " tcpflags %d mask %d", r->tcp_flags_value, r->tcp_flags_mask);
2391           }
2392           out0 = format(out0, "\n");
2393         }
2394
2395         if (i<vec_len(am->input_sw_if_index_vec_by_acl)) {
2396           out0 = format(out0, "  applied inbound on sw_if_index: ");
2397           vec_foreach(pj, am->input_sw_if_index_vec_by_acl[i]) {
2398             out0 = format(out0, "%d ", *pj);
2399           }
2400           out0 = format(out0, "\n");
2401         }
2402         if (i<vec_len(am->output_sw_if_index_vec_by_acl)) {
2403           out0 = format(out0, "  applied outbound on sw_if_index: ");
2404           vec_foreach(pj, am->output_sw_if_index_vec_by_acl[i]) {
2405             out0 = format(out0, "%d ", *pj);
2406           }
2407           out0 = format(out0, "\n");
2408         }
2409       }
2410       vec_terminate_c_string(out0);
2411       vlib_cli_output(vm, "\n%s\n", out0);
2412       vec_free(out0);
2413     }
2414   else if (unformat (input, "memory"))
2415     {
2416       vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
2417       if (am->acl_mheap) {
2418         vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
2419       } else {
2420         vlib_cli_output (vm, " Not initialized\n");
2421       }
2422       vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
2423       if (am->hash_lookup_mheap) {
2424         vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
2425       } else {
2426         vlib_cli_output (vm, " Not initialized\n");
2427       }
2428     }
2429   else if (unformat (input, "tables"))
2430     {
2431       ace_mask_type_entry_t *mte;
2432       u32 acl_index = ~0;
2433       u32 sw_if_index = ~0;
2434       int show_acl_hash_info = 0;
2435       int show_applied_info = 0;
2436       int show_mask_type = 0;
2437       int show_bihash = 0;
2438       u32 show_bihash_verbose = 0;
2439
2440       if (unformat (input, "acl")) {
2441         show_acl_hash_info = 1;
2442         /* mask-type is handy to see as well right there */
2443         show_mask_type = 1;
2444         unformat (input, "index %u", &acl_index);
2445       } else if (unformat (input, "applied")) {
2446         show_applied_info = 1;
2447         unformat (input, "sw_if_index %u", &sw_if_index);
2448       } else if (unformat (input, "mask")) {
2449         show_mask_type = 1;
2450       } else if (unformat (input, "hash")) {
2451         show_bihash = 1;
2452         unformat (input, "verbose %u", &show_bihash_verbose);
2453       }
2454
2455       if ( ! (show_mask_type || show_acl_hash_info || show_applied_info || show_bihash) ) {
2456         /* if no qualifiers specified, show all */
2457         show_mask_type = 1;
2458         show_acl_hash_info = 1;
2459         show_applied_info = 1;
2460         show_bihash = 1;
2461       }
2462
2463       if (show_mask_type) {
2464         vlib_cli_output(vm, "Mask-type entries:");
2465         /* *INDENT-OFF* */
2466         pool_foreach(mte, am->ace_mask_type_pool,
2467         ({
2468           vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
2469                         mte - am->ace_mask_type_pool,
2470                         mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
2471                         mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
2472         }));
2473         /* *INDENT-ON* */
2474       }
2475
2476       if (show_acl_hash_info) {
2477         u32 i,j;
2478         u8 * out0 = format(0, "");
2479         u64 *m;
2480         out0 = format(out0, "Mask-ready ACL representations\n");
2481         for (i=0; i< vec_len(am->hash_acl_infos); i++) {
2482           if ((acl_index != ~0) && (acl_index != i)) {
2483             continue;
2484           }
2485           hash_acl_info_t *ha = &am->hash_acl_infos[i];
2486           out0 = format(out0, "acl-index %u bitmask-ready layout\n", i);
2487           out0 = format(out0, "  applied  inbound on sw_if_index list: %U\n", format_vec32, ha->inbound_sw_if_index_list, "%d");
2488           out0 = format(out0, "  applied outbound on sw_if_index list: %U\n", format_vec32, ha->outbound_sw_if_index_list, "%d");
2489           out0 = format(out0, "  mask type index bitmap: %U\n", format_bitmap_hex, ha->mask_type_index_bitmap);
2490           for(j=0; j<vec_len(ha->rules); j++) {
2491             hash_ace_info_t *pa = &ha->rules[j];
2492             m = (u64 *)&pa->match;
2493             out0 = format(out0, "    %4d: %016llx %016llx %016llx %016llx %016llx %016llx mask index %d acl %d rule %d action %d src/dst portrange not ^2: %d,%d\n",
2494                                 j, m[0], m[1], m[2], m[3], m[4], m[5], pa->mask_type_index,
2495                                 pa->acl_index, pa->ace_index, pa->action,
2496                                 pa->src_portrange_not_powerof2, pa->dst_portrange_not_powerof2);
2497           }
2498         }
2499         vec_terminate_c_string(out0);
2500         vlib_cli_output(vm, "\n%s\n", out0);
2501         vec_free(out0);
2502       }
2503
2504       if (show_applied_info) {
2505         u32 swi, j;
2506         u8 * out0 = format(0, "");
2507         out0 = format(out0, "Applied lookup entries for interfaces\n");
2508
2509         for(swi = 0; (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) ||
2510                    (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) ||
2511                    (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) ||
2512                    (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)); swi++) {
2513           if ((sw_if_index != ~0) && (sw_if_index != swi)) {
2514             continue;
2515           }
2516           out0 = format(out0, "sw_if_index %d:\n", swi);
2517           if (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) {
2518             applied_hash_acl_info_t *pal = &am->input_applied_hash_acl_info_by_sw_if_index[swi];
2519             out0 = format(out0, "  input lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2520             out0 = format(out0, "  input applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2521           }
2522           if (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) {
2523             out0 = format(out0, "  input lookup applied entries:\n");
2524             for(j=0; j<vec_len(am->input_hash_entry_vec_by_sw_if_index[swi]); j++) {
2525               applied_hash_ace_entry_t *pae = &am->input_hash_entry_vec_by_sw_if_index[swi][j];
2526               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
2527                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2528                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
2529             }
2530           }
2531
2532           if (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) {
2533             applied_hash_acl_info_t *pal = &am->output_applied_hash_acl_info_by_sw_if_index[swi];
2534             out0 = format(out0, "  output lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2535             out0 = format(out0, "  output applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2536           }
2537           if (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)) {
2538             out0 = format(out0, "  output lookup applied entries:\n");
2539             for(j=0; j<vec_len(am->output_hash_entry_vec_by_sw_if_index[swi]); j++) {
2540               applied_hash_ace_entry_t *pae = &am->output_hash_entry_vec_by_sw_if_index[swi][j];
2541               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
2542                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2543                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
2544             }
2545           }
2546
2547         }
2548         vec_terminate_c_string(out0);
2549         vlib_cli_output(vm, "\n%s\n", out0);
2550         vec_free(out0);
2551       }
2552
2553       if (show_bihash) {
2554         show_hash_acl_hash(vm, am, show_bihash_verbose);
2555       }
2556     }
2557   return error;
2558 }
2559
2560 static clib_error_t *
2561 acl_clear_aclplugin_fn (vlib_main_t * vm,
2562                               unformat_input_t * input,
2563                               vlib_cli_command_t * cmd)
2564 {
2565   clib_error_t *error = 0;
2566   acl_main_t *am = &acl_main;
2567   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2568                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
2569   return error;
2570 }
2571
2572  /* *INDENT-OFF* */
2573 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
2574     .path = "set acl-plugin",
2575     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
2576     .function = acl_set_aclplugin_fn,
2577 };
2578
2579 VLIB_CLI_COMMAND (aclplugin_show_command, static) = {
2580     .path = "show acl-plugin",
2581     .short_help = "show acl-plugin {sessions|acl|interface|tables}",
2582     .function = acl_show_aclplugin_fn,
2583 };
2584
2585 VLIB_CLI_COMMAND (aclplugin_show_macip_command, static) = {
2586     .path = "show acl-plugin macip",
2587     .short_help = "show acl-plugin macip {acl|interface}",
2588     .function = acl_show_aclplugin_macip_fn,
2589 };
2590
2591
2592 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
2593     .path = "clear acl-plugin sessions",
2594     .short_help = "clear acl-plugin sessions",
2595     .function = acl_clear_aclplugin_fn,
2596 };
2597 /* *INDENT-ON* */
2598
2599 static clib_error_t *
2600 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
2601 {
2602   acl_main_t *am = &acl_main;
2603   u32 conn_table_hash_buckets;
2604   u32 conn_table_hash_memory_size;
2605   u32 conn_table_max_entries;
2606   u32 main_heap_size;
2607   u32 hash_heap_size;
2608   u32 hash_lookup_hash_buckets;
2609   u32 hash_lookup_hash_memory;
2610
2611   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2612     {
2613       if (unformat (input, "connection hash buckets %d", &conn_table_hash_buckets))
2614         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
2615       else if (unformat (input, "connection hash memory %d",
2616                          &conn_table_hash_memory_size))
2617         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
2618       else if (unformat (input, "connection count max %d",
2619                          &conn_table_max_entries))
2620         am->fa_conn_table_max_entries = conn_table_max_entries;
2621       else if (unformat (input, "main heap size %d",
2622                          &main_heap_size))
2623         am->acl_mheap_size = main_heap_size;
2624       else if (unformat (input, "hash lookup heap size %d",
2625                          &hash_heap_size))
2626         am->hash_lookup_mheap_size = hash_heap_size;
2627       else if (unformat (input, "hash lookup hash buckets %d",
2628                          &hash_lookup_hash_buckets))
2629         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
2630       else if (unformat (input, "hash lookup hash memory %d",
2631                          &hash_lookup_hash_memory))
2632         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
2633       else
2634         return clib_error_return (0, "unknown input '%U'",
2635                                   format_unformat_error, input);
2636     }
2637   return 0;
2638 }
2639 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
2640
2641 static clib_error_t *
2642 acl_init (vlib_main_t * vm)
2643 {
2644   acl_main_t *am = &acl_main;
2645   clib_error_t *error = 0;
2646   memset (am, 0, sizeof (*am));
2647   am->vlib_main = vm;
2648   am->vnet_main = vnet_get_main ();
2649
2650   u8 *name = format (0, "acl_%08x%c", api_version, 0);
2651
2652   /* Ask for a correctly-sized block of API message decode slots */
2653   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
2654                                             VL_MSG_FIRST_AVAILABLE);
2655
2656   error = acl_plugin_api_hookup (vm);
2657
2658  /* Add our API messages to the global name_crc hash table */
2659   setup_message_id_table (am, &api_main);
2660
2661   vec_free (name);
2662
2663   acl_setup_fa_nodes();
2664
2665   am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
2666   am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
2667
2668   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
2669   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
2670
2671   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
2672   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
2673   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;
2674
2675   am->fa_conn_table_hash_num_buckets = ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
2676   am->fa_conn_table_hash_memory_size = ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
2677   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
2678   vlib_thread_main_t *tm = vlib_get_thread_main ();
2679   vec_validate(am->per_worker_data, tm->n_vlib_mains-1);
2680   {
2681     u16 wk;
2682     u8 tt;
2683     for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2684       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2685       vec_validate(pw->fa_conn_list_head, ACL_N_TIMEOUTS-1);
2686       vec_validate(pw->fa_conn_list_tail, ACL_N_TIMEOUTS-1);
2687       for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2688         pw->fa_conn_list_head[tt] = ~0;
2689         pw->fa_conn_list_tail[tt] = ~0;
2690       }
2691     }
2692   }
2693
2694   am->fa_min_deleted_sessions_per_interval = ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
2695   am->fa_max_deleted_sessions_per_interval = ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
2696   am->fa_cleaner_wait_time_increment = ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
2697
2698   am->fa_cleaner_cnt_delete_by_sw_index = 0;
2699   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
2700   am->fa_cleaner_cnt_unknown_event = 0;
2701   am->fa_cleaner_cnt_timer_restarted = 0;
2702   am->fa_cleaner_cnt_wait_with_timeout = 0;
2703
2704
2705 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
2706   foreach_acl_eh
2707 #undef _
2708
2709   am->l4_match_nonfirst_fragment = 1;
2710
2711   /* use the new fancy hash-based matching */
2712   am->use_hash_acl_matching = 1;
2713
2714   return error;
2715 }
2716
2717 VLIB_INIT_FUNCTION (acl_init);