ACL plugin enable macip for ip4/ip6 traffic
[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   if (is_add)
898     {
899       rv =
900         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
901       if (rv == 0)
902         {
903           hash_acl_apply(am, sw_if_index, is_input, acl_list_index);
904         }
905     }
906   else
907     {
908       hash_acl_unapply(am, sw_if_index, is_input, acl_list_index);
909       rv =
910         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
911     }
912   return rv;
913 }
914
915
916 typedef struct
917 {
918   u8 is_ipv6;
919   u8 mac_mask[6];
920   u8 prefix_len;
921   u32 count;
922   u32 table_index;
923   u32 arp_table_index;
924 } macip_match_type_t;
925
926 static u32
927 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
928                        u8 is_ipv6)
929 {
930   u32 i;
931   if (mv)
932     {
933       for (i = 0; i < vec_len (mv); i++)
934         {
935           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
936               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
937             {
938               return i;
939             }
940         }
941     }
942   return ~0;
943 }
944
945
946 /* Get metric used to sort match types.
947    The more specific and the more often seen - the bigger the metric */
948 static int
949 match_type_metric (macip_match_type_t * m)
950 {
951    unsigned int mac_bits_set = 0;
952    unsigned int mac_byte;
953    int i;
954    for (i=0; i<6; i++)
955      {
956        mac_byte = m->mac_mask[i];
957        for (; mac_byte; mac_byte >>= 1)
958          mac_bits_set += mac_byte & 1;
959      }
960    /*
961     * Attempt to place the more specific and the more used rules on top.
962     * There are obvious caveat corner cases to this, but they do not
963     * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
964     * going with a wildcard IPv4 with a specific MAC).
965     */
966    return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
967 }
968
969 static int
970 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
971 {
972   /* Ascending sort based on the metric values */
973   return match_type_metric (m1) - match_type_metric (m2);
974 }
975
976 /* Get the offset of L3 source within ethernet packet */
977 static int
978 get_l3_src_offset(int is6)
979 {
980   if(is6)
981     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
982   else
983     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
984 }
985
986 static int
987 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
988 {
989   macip_match_type_t *mvec = NULL;
990   macip_match_type_t *mt;
991   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
992   int i;
993   u32 match_type_index;
994   u32 last_table;
995   u8 mask[5 * 16];
996   vnet_classify_main_t *cm = &vnet_classify_main;
997
998   /* Count the number of different types of rules */
999   for (i = 0; i < a->count; i++)
1000     {
1001       if (~0 ==
1002           (match_type_index =
1003            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1004                                   a->rules[i].src_prefixlen,
1005                                   a->rules[i].is_ipv6)))
1006         {
1007           match_type_index = vec_len (mvec);
1008           vec_validate (mvec, match_type_index);
1009           memcpy (mvec[match_type_index].mac_mask,
1010                   a->rules[i].src_mac_mask, 6);
1011           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1012           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1013           mvec[match_type_index].table_index = ~0;
1014         }
1015       mvec[match_type_index].count++;
1016     }
1017   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1018   vec_sort_with_function (mvec, match_type_compare);
1019   /* Create the classifier tables */
1020   last_table = ~0;
1021   /* First add ARP tables */
1022   vec_foreach (mt, mvec)
1023   {
1024     int mask_len;
1025     int is6 = mt->is_ipv6;
1026
1027     mt->arp_table_index = ~0;
1028     if (!is6)
1029       {
1030         memset (mask, 0, sizeof (mask));
1031         memcpy (&mask[6], mt->mac_mask, 6);
1032         memset (&mask[12], 0xff, 2); /* ethernet protocol */
1033         memcpy (&mask[14 + 8], mt->mac_mask, 6);
1034
1035         for (i = 0; i < (mt->prefix_len / 8); i++)
1036           mask[14 + 14 + i] = 0xff;
1037         if (mt->prefix_len % 8)
1038           mask[14 + 14 + (mt->prefix_len / 8)] = 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1039
1040         mask_len = ((14 + 14 + ((mt->prefix_len+7) / 8) +
1041                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1042         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1043                                (~0 == last_table) ? 0 : ~0, &mt->arp_table_index,
1044                                1);
1045         last_table = mt->arp_table_index;
1046       }
1047   }
1048   /* Now add IP[46] tables */
1049   vec_foreach (mt, mvec)
1050   {
1051     int mask_len;
1052     int is6 = mt->is_ipv6;
1053     int l3_src_offs = get_l3_src_offset(is6);
1054     memset (mask, 0, sizeof (mask));
1055     memcpy (&mask[6], mt->mac_mask, 6);
1056     for (i = 0; i < (mt->prefix_len / 8); i++)
1057       {
1058         mask[l3_src_offs + i] = 0xff;
1059       }
1060     if (mt->prefix_len % 8)
1061       {
1062         mask[l3_src_offs + (mt->prefix_len / 8)] =
1063           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1064       }
1065     /*
1066      * Round-up the number of bytes needed to store the prefix,
1067      * and round up the number of vectors too
1068      */
1069     mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) +
1070                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
1071     acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1072                                 (~0 == last_table) ? 0 : ~0, &mt->table_index,
1073                                 1);
1074     last_table = mt->table_index;
1075   }
1076   a->ip4_table_index = last_table;
1077   a->ip6_table_index = last_table;
1078   a->l2_table_index = last_table;
1079
1080   /* Populate the classifier tables with rules from the MACIP ACL */
1081   for (i = 0; i < a->count; i++)
1082     {
1083       u32 action = 0;
1084       u32 metadata = 0;
1085       int is6 = a->rules[i].is_ipv6;
1086       int l3_src_offs = get_l3_src_offset(is6);
1087       memset (mask, 0, sizeof (mask));
1088       memcpy (&mask[6], a->rules[i].src_mac, 6);
1089       memset (&mask[12], 0xff, 2); /* ethernet protocol */
1090       if (is6)
1091         {
1092           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1093           mask[12] = 0x86;
1094           mask[13] = 0xdd;
1095         }
1096       else
1097         {
1098           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1099           mask[12] = 0x08;
1100           mask[13] = 0x00;
1101         }
1102       match_type_index =
1103         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1104                                a->rules[i].src_prefixlen,
1105                                a->rules[i].is_ipv6);
1106       ASSERT(match_type_index != ~0);
1107       /* add session to table mvec[match_type_index].table_index; */
1108       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
1109                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
1110                                      0, action, metadata, 1);
1111       /* add ARP table entry too */
1112       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1113         {
1114           memset (mask, 0, sizeof (mask));
1115           memcpy (&mask[6], a->rules[i].src_mac, 6);
1116           mask[12] = 0x08;
1117           mask[13] = 0x06;
1118           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
1119           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
1120           vnet_classify_add_del_session (cm, mvec[match_type_index].arp_table_index,
1121                                     mask, a->rules[i].is_permit ? ~0 : 0, i,
1122                                     0, action, metadata, 1);
1123         }
1124     }
1125   return 0;
1126 }
1127
1128 static void
1129 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1130 {
1131   vnet_classify_main_t *cm = &vnet_classify_main;
1132   macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1133
1134   if (a->ip4_table_index != ~0)
1135     {
1136       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
1137       a->ip4_table_index = ~0;
1138     }
1139   if (a->ip6_table_index != ~0)
1140     {
1141       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
1142       a->ip6_table_index = ~0;
1143     }
1144   if (a->l2_table_index != ~0)
1145     {
1146       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
1147       a->l2_table_index = ~0;
1148     }
1149 }
1150
1151 static int
1152 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1153                     u32 * acl_list_index, u8 * tag)
1154 {
1155   acl_main_t *am = &acl_main;
1156   macip_acl_list_t *a;
1157   macip_acl_rule_t *r;
1158   macip_acl_rule_t *acl_new_rules = 0;
1159   int i;
1160
1161   if (*acl_list_index != ~0)
1162     {
1163       /* They supplied some number, let's see if this MACIP ACL exists */
1164       if (pool_is_free_index (am->macip_acls, *acl_list_index))
1165   {
1166     /* tried to replace a non-existent ACL, no point doing anything */
1167           clib_warning("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)", *acl_list_index, tag);
1168     return -1;
1169   }
1170     }
1171
1172   if (0 == count) {
1173     clib_warning("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)", tag);
1174   }
1175   void *oldheap = acl_set_heap(am);
1176   /* Create and populate the rules */
1177   if (count > 0)
1178     vec_validate(acl_new_rules, count-1);
1179
1180   for (i = 0; i < count; i++)
1181     {
1182       r = &acl_new_rules[i];
1183       r->is_permit = rules[i].is_permit;
1184       r->is_ipv6 = rules[i].is_ipv6;
1185       memcpy (&r->src_mac, rules[i].src_mac, 6);
1186       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1187       if(rules[i].is_ipv6)
1188         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1189       else
1190         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1191       r->src_prefixlen = rules[i].src_ip_prefix_len;
1192     }
1193
1194   if (~0 == *acl_list_index)
1195     {
1196       /* Get ACL index */
1197       pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1198       memset (a, 0, sizeof (*a));
1199       /* Will return the newly allocated ACL index */
1200       *acl_list_index = a - am->macip_acls;
1201     }
1202   else
1203     {
1204       a = pool_elt_at_index (am->macip_acls, *acl_list_index);
1205       if (a->rules)
1206         {
1207           vec_free (a->rules);
1208         }
1209       macip_destroy_classify_tables (am, *acl_list_index);
1210     }
1211
1212   a->rules = acl_new_rules;
1213   a->count = count;
1214   memcpy (a->tag, tag, sizeof (a->tag));
1215
1216   /* Create and populate the classifer tables */
1217   macip_create_classify_tables (am, *acl_list_index);
1218   clib_mem_set_heap (oldheap);
1219   return 0;
1220 }
1221
1222
1223 /* No check for validity of sw_if_index - the callers were supposed to validate */
1224
1225 static int
1226 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1227 {
1228   int rv;
1229   u32 macip_acl_index;
1230   macip_acl_list_t *a;
1231   void *oldheap = acl_set_heap(am);
1232   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1233   clib_mem_set_heap (oldheap);
1234   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1235   /* No point in deleting MACIP ACL which is not applied */
1236   if (~0 == macip_acl_index)
1237     return -1;
1238   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1239   /* remove the classifier tables off the interface L2 ACL */
1240   rv =
1241     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1242                               a->ip6_table_index, a->l2_table_index, 0);
1243   /* Unset the MACIP ACL index */
1244   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1245   return rv;
1246 }
1247
1248 /* No check for validity of sw_if_index - the callers were supposed to validate */
1249
1250 static int
1251 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1252                              u32 macip_acl_index)
1253 {
1254   macip_acl_list_t *a;
1255   int rv;
1256   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1257     {
1258       return -1;
1259     }
1260   void *oldheap = acl_set_heap(am);
1261   a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1262   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1263   clib_mem_set_heap (oldheap);
1264   /* If there already a MACIP ACL applied, unapply it */
1265   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1266     macip_acl_interface_del_acl(am, sw_if_index);
1267   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1268
1269   /* Apply the classifier tables for L2 ACLs */
1270   rv =
1271     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1272                               a->ip6_table_index, a->l2_table_index, 1);
1273   return rv;
1274 }
1275
1276 static int
1277 macip_acl_del_list (u32 acl_list_index)
1278 {
1279   acl_main_t *am = &acl_main;
1280   macip_acl_list_t *a;
1281   int i;
1282   if (pool_is_free_index (am->macip_acls, acl_list_index))
1283     {
1284       return -1;
1285     }
1286
1287   /* delete any references to the ACL */
1288   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1289     {
1290       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1291         {
1292           macip_acl_interface_del_acl (am, i);
1293         }
1294     }
1295
1296   void *oldheap = acl_set_heap(am);
1297   /* Now that classifier tables are detached, clean them up */
1298   macip_destroy_classify_tables (am, acl_list_index);
1299
1300   /* now we can delete the ACL itself */
1301   a = pool_elt_at_index (am->macip_acls, acl_list_index);
1302   if (a->rules)
1303     {
1304       vec_free (a->rules);
1305     }
1306   pool_put (am->macip_acls, a);
1307   clib_mem_set_heap (oldheap);
1308   return 0;
1309 }
1310
1311
1312 static int
1313 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1314                                  u32 acl_list_index)
1315 {
1316   acl_main_t *am = &acl_main;
1317   int rv = -1;
1318   if (is_add)
1319     {
1320       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1321     }
1322   else
1323     {
1324       rv = macip_acl_interface_del_acl (am, sw_if_index);
1325     }
1326   return rv;
1327 }
1328
1329 /*
1330  * If the client does not allocate enough memory for a variable-length
1331  * message, and then proceed to use it as if the full memory allocated,
1332  * absent the check we happily consume that on the VPP side, and go
1333  * along as if nothing happened. However, the resulting
1334  * effects range from just garbage in the API decode
1335  * (because the decoder snoops too far), to potential memory
1336  * corruptions.
1337  *
1338  * This verifies that the actual length of the message is
1339  * at least expected_len, and complains loudly if it is not.
1340  *
1341  * A failing check here is 100% a software bug on the API user side,
1342  * so we might as well yell.
1343  *
1344  */
1345 static int verify_message_len(void *mp, u32 expected_len, char *where)
1346 {
1347   u32 supplied_len = vl_msg_api_get_msg_length (mp);
1348   if (supplied_len < expected_len) {
1349       clib_warning("%s: Supplied message length %d is less than expected %d",
1350                    where, supplied_len, expected_len);
1351       return 0;
1352   } else {
1353       return 1;
1354   }
1355 }
1356
1357 /* API message handler */
1358 static void
1359 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1360 {
1361   vl_api_acl_add_replace_reply_t *rmp;
1362   acl_main_t *am = &acl_main;
1363   int rv;
1364   u32 acl_list_index = ntohl (mp->acl_index);
1365   u32 acl_count = ntohl (mp->count);
1366   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1367
1368   if (verify_message_len(mp, expected_len, "acl_add_replace")) {
1369       rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1370   } else {
1371       rv = VNET_API_ERROR_INVALID_VALUE;
1372   }
1373
1374   /* *INDENT-OFF* */
1375   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1376   ({
1377     rmp->acl_index = htonl(acl_list_index);
1378   }));
1379   /* *INDENT-ON* */
1380 }
1381
1382 static void
1383 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1384 {
1385   acl_main_t *am = &acl_main;
1386   vl_api_acl_del_reply_t *rmp;
1387   int rv;
1388
1389   rv = acl_del_list (ntohl (mp->acl_index));
1390
1391   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1392 }
1393
1394 static void
1395 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1396 {
1397   acl_main_t *am = &acl_main;
1398   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1399   u32 sw_if_index = ntohl (mp->sw_if_index);
1400   vl_api_acl_interface_add_del_reply_t *rmp;
1401   int rv = -1;
1402
1403   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1404     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1405   else
1406     rv =
1407       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1408                                      mp->is_input, ntohl (mp->acl_index));
1409
1410   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1411 }
1412
1413 static void
1414 vl_api_acl_interface_set_acl_list_t_handler
1415   (vl_api_acl_interface_set_acl_list_t * mp)
1416 {
1417   acl_main_t *am = &acl_main;
1418   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1419   int rv = 0;
1420   int i;
1421   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1422   u32 sw_if_index = ntohl (mp->sw_if_index);
1423
1424   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1425     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1426   else
1427     {
1428       acl_interface_reset_inout_acls (sw_if_index, 0);
1429       acl_interface_reset_inout_acls (sw_if_index, 1);
1430
1431       for (i = 0; i < mp->count; i++)
1432         {
1433           if(acl_is_not_defined(am, ntohl (mp->acls[i]))) {
1434             /* ACL does not exist, so we can not apply it */
1435             rv = -1;
1436           }
1437         }
1438       if (0 == rv) {
1439         for (i = 0; i < mp->count; i++)
1440           {
1441             acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1442                                        ntohl (mp->acls[i]));
1443           }
1444       }
1445     }
1446
1447   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1448 }
1449
1450 static void
1451 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1452 {
1453   api_rule->is_permit = r->is_permit;
1454   api_rule->is_ipv6 = r->is_ipv6;
1455   if(r->is_ipv6)
1456     {
1457       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1458       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1459     }
1460   else
1461     {
1462       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1463       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1464     }
1465   api_rule->src_ip_prefix_len = r->src_prefixlen;
1466   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1467   api_rule->proto = r->proto;
1468   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1469   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1470   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1471   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1472   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1473   api_rule->tcp_flags_value = r->tcp_flags_value;
1474 }
1475
1476 static void
1477 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1478                   acl_list_t * acl, u32 context)
1479 {
1480   vl_api_acl_details_t *mp;
1481   vl_api_acl_rule_t *rules;
1482   int i;
1483   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1484   void *oldheap = acl_set_heap(am);
1485
1486   mp = vl_msg_api_alloc (msg_size);
1487   memset (mp, 0, msg_size);
1488   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1489
1490   /* fill in the message */
1491   mp->context = context;
1492   mp->count = htonl (acl->count);
1493   mp->acl_index = htonl (acl - am->acls);
1494   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1495   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1496   rules = mp->r;
1497   for (i = 0; i < acl->count; i++)
1498     {
1499       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1500     }
1501
1502   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1503   clib_mem_set_heap (oldheap);
1504   vl_msg_api_send_shmem (q, (u8 *) & mp);
1505 }
1506
1507
1508 static void
1509 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1510 {
1511   acl_main_t *am = &acl_main;
1512   u32 acl_index;
1513   acl_list_t *acl;
1514
1515   int rv = -1;
1516   unix_shared_memory_queue_t *q;
1517
1518   q = vl_api_client_index_to_input_queue (mp->client_index);
1519   if (q == 0)
1520     {
1521       return;
1522     }
1523
1524   if (mp->acl_index == ~0)
1525     {
1526     /* *INDENT-OFF* */
1527     /* Just dump all ACLs */
1528     pool_foreach (acl, am->acls,
1529     ({
1530       send_acl_details(am, q, acl, mp->context);
1531     }));
1532     /* *INDENT-ON* */
1533     }
1534   else
1535     {
1536       acl_index = ntohl (mp->acl_index);
1537       if (!pool_is_free_index (am->acls, acl_index))
1538        {
1539          acl = pool_elt_at_index (am->acls, acl_index);
1540          send_acl_details (am, q, acl, mp->context);
1541        }
1542     }
1543
1544   if (rv == -1)
1545     {
1546       /* FIXME API: should we signal an error here at all ? */
1547       return;
1548     }
1549 }
1550
1551 static void
1552 send_acl_interface_list_details (acl_main_t * am,
1553                                  unix_shared_memory_queue_t * q,
1554                                  u32 sw_if_index, u32 context)
1555 {
1556   vl_api_acl_interface_list_details_t *mp;
1557   int msg_size;
1558   int n_input;
1559   int n_output;
1560   int count;
1561   int i = 0;
1562   void *oldheap = acl_set_heap(am);
1563
1564   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1565   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1566
1567   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1568   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1569   count = n_input + n_output;
1570
1571   msg_size = sizeof (*mp);
1572   msg_size += sizeof (mp->acls[0]) * count;
1573
1574   mp = vl_msg_api_alloc (msg_size);
1575   memset (mp, 0, msg_size);
1576   mp->_vl_msg_id =
1577     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1578
1579   /* fill in the message */
1580   mp->context = context;
1581   mp->sw_if_index = htonl (sw_if_index);
1582   mp->count = count;
1583   mp->n_input = n_input;
1584   for (i = 0; i < n_input; i++)
1585     {
1586       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1587     }
1588   for (i = 0; i < n_output; i++)
1589     {
1590       mp->acls[n_input + i] =
1591         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1592     }
1593   clib_mem_set_heap (oldheap);
1594   vl_msg_api_send_shmem (q, (u8 *) & mp);
1595 }
1596
1597 static void
1598 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1599                                           mp)
1600 {
1601   acl_main_t *am = &acl_main;
1602   vnet_sw_interface_t *swif;
1603   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1604
1605   u32 sw_if_index;
1606   unix_shared_memory_queue_t *q;
1607
1608   q = vl_api_client_index_to_input_queue (mp->client_index);
1609   if (q == 0)
1610     {
1611       return;
1612     }
1613
1614   if (mp->sw_if_index == ~0)
1615     {
1616     /* *INDENT-OFF* */
1617     pool_foreach (swif, im->sw_interfaces,
1618     ({
1619       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1620     }));
1621     /* *INDENT-ON* */
1622     }
1623   else
1624     {
1625       sw_if_index = ntohl (mp->sw_if_index);
1626       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1627         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1628     }
1629 }
1630
1631 /* MACIP ACL API handlers */
1632
1633 static void
1634 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1635 {
1636   vl_api_macip_acl_add_reply_t *rmp;
1637   acl_main_t *am = &acl_main;
1638   int rv;
1639   u32 acl_list_index = ~0;
1640   u32 acl_count = ntohl (mp->count);
1641   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1642
1643   if (verify_message_len(mp, expected_len, "macip_acl_add")) {
1644       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1645   } else {
1646       rv = VNET_API_ERROR_INVALID_VALUE;
1647   }
1648
1649   /* *INDENT-OFF* */
1650   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1651   ({
1652     rmp->acl_index = htonl(acl_list_index);
1653   }));
1654   /* *INDENT-ON* */
1655 }
1656
1657 static void
1658 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
1659 {
1660   vl_api_macip_acl_add_replace_reply_t *rmp;
1661   acl_main_t *am = &acl_main;
1662   int rv;
1663   u32 acl_list_index = ntohl (mp->acl_index);
1664   u32 acl_count = ntohl (mp->count);
1665   u32 expected_len = sizeof(*mp) + acl_count*sizeof(mp->r[0]);
1666
1667   if (verify_message_len(mp, expected_len, "macip_acl_add_replace")) {
1668       rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
1669   } else {
1670       rv = VNET_API_ERROR_INVALID_VALUE;
1671   }
1672
1673   /* *INDENT-OFF* */
1674   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
1675   ({
1676     rmp->acl_index = htonl(acl_list_index);
1677   }));
1678   /* *INDENT-ON* */
1679 }
1680
1681 static void
1682 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1683 {
1684   acl_main_t *am = &acl_main;
1685   vl_api_macip_acl_del_reply_t *rmp;
1686   int rv;
1687
1688   rv = macip_acl_del_list (ntohl (mp->acl_index));
1689
1690   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1691 }
1692
1693 static void
1694 vl_api_macip_acl_interface_add_del_t_handler
1695   (vl_api_macip_acl_interface_add_del_t * mp)
1696 {
1697   acl_main_t *am = &acl_main;
1698   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1699   int rv = -1;
1700   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1701   u32 sw_if_index = ntohl (mp->sw_if_index);
1702
1703   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1704     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1705   else
1706     rv =
1707       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1708                                      ntohl (mp->acl_index));
1709
1710   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1711 }
1712
1713 static void
1714 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1715                         macip_acl_list_t * acl, u32 context)
1716 {
1717   vl_api_macip_acl_details_t *mp;
1718   vl_api_macip_acl_rule_t *rules;
1719   macip_acl_rule_t *r;
1720   int i;
1721   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1722
1723   mp = vl_msg_api_alloc (msg_size);
1724   memset (mp, 0, msg_size);
1725   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1726
1727   /* fill in the message */
1728   mp->context = context;
1729   if (acl)
1730     {
1731       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1732       mp->count = htonl (acl->count);
1733       mp->acl_index = htonl (acl - am->macip_acls);
1734       rules = mp->r;
1735       for (i = 0; i < acl->count; i++)
1736         {
1737           r = &acl->rules[i];
1738           rules[i].is_permit = r->is_permit;
1739           rules[i].is_ipv6 = r->is_ipv6;
1740           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1741           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1742                   sizeof (r->src_mac_mask));
1743           if (r->is_ipv6)
1744             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1745                   sizeof (r->src_ip_addr.ip6));
1746           else
1747             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1748                   sizeof (r->src_ip_addr.ip4));
1749           rules[i].src_ip_prefix_len = r->src_prefixlen;
1750         }
1751     }
1752   else
1753     {
1754       /* No martini, no party - no ACL applied to this interface. */
1755       mp->acl_index = ~0;
1756       mp->count = 0;
1757     }
1758
1759   vl_msg_api_send_shmem (q, (u8 *) & mp);
1760 }
1761
1762
1763 static void
1764 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1765 {
1766   acl_main_t *am = &acl_main;
1767   macip_acl_list_t *acl;
1768
1769   unix_shared_memory_queue_t *q;
1770
1771   q = vl_api_client_index_to_input_queue (mp->client_index);
1772   if (q == 0)
1773     {
1774       return;
1775     }
1776
1777   if (mp->acl_index == ~0)
1778     {
1779       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1780       pool_foreach (acl, am->macip_acls, (
1781                                            {
1782                                            send_macip_acl_details (am, q, acl,
1783                                                                    mp->
1784                                                                    context);}
1785                     ));
1786       /* *INDENT-ON* */
1787     }
1788   else
1789     {
1790       u32 acl_index = ntohl (mp->acl_index);
1791       if (!pool_is_free_index (am->macip_acls, acl_index))
1792        {
1793          acl = pool_elt_at_index (am->macip_acls, acl_index);
1794          send_macip_acl_details (am, q, acl, mp->context);
1795        }
1796     }
1797 }
1798
1799 static void
1800 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1801                                           mp)
1802 {
1803   acl_main_t *am = &acl_main;
1804   vl_api_macip_acl_interface_get_reply_t *rmp;
1805   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1806   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1807   unix_shared_memory_queue_t *q;
1808   int i;
1809
1810   q = vl_api_client_index_to_input_queue (mp->client_index);
1811   if (q == 0)
1812     {
1813       return;
1814     }
1815
1816   rmp = vl_msg_api_alloc (msg_size);
1817   memset (rmp, 0, msg_size);
1818   rmp->_vl_msg_id =
1819     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1820   rmp->context = mp->context;
1821   rmp->count = htonl (count);
1822   for (i = 0; i < count; i++)
1823     {
1824       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1825     }
1826
1827   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1828 }
1829
1830 static void
1831 send_macip_acl_interface_list_details (acl_main_t * am,
1832                                        unix_shared_memory_queue_t * q,
1833                                        u32 sw_if_index,
1834                                        u32 acl_index,
1835                                        u32 context)
1836 {
1837   vl_api_macip_acl_interface_list_details_t *rmp;
1838   /* at this time there is only ever 1 mac ip acl per interface */
1839   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
1840
1841   rmp = vl_msg_api_alloc (msg_size);
1842   memset (rmp, 0, msg_size);
1843   rmp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1844
1845   /* fill in the message */
1846   rmp->context = context;
1847   rmp->count = 1;
1848   rmp->sw_if_index = htonl (sw_if_index);
1849   rmp->acls[0] = htonl (acl_index);
1850
1851   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1852 }
1853
1854 static void
1855 vl_api_macip_acl_interface_list_dump_t_handler (vl_api_macip_acl_interface_list_dump_t *mp)
1856 {
1857   unix_shared_memory_queue_t *q;
1858   acl_main_t *am = &acl_main;
1859   u32 sw_if_index = ntohl (mp->sw_if_index);
1860
1861   q = vl_api_client_index_to_input_queue (mp->client_index);
1862   if (q == 0)
1863     {
1864       return;
1865     }
1866
1867   if (sw_if_index == ~0)
1868     {
1869       vec_foreach_index(sw_if_index, am->macip_acl_by_sw_if_index)
1870         {
1871           if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1872             {
1873               send_macip_acl_interface_list_details(am, q,  sw_if_index,
1874                                                     am->macip_acl_by_sw_if_index[sw_if_index],
1875                                                     mp->context);
1876             }
1877         }
1878     }
1879   else
1880     {
1881       if (vec_len(am->macip_acl_by_sw_if_index) > sw_if_index)
1882         {
1883           send_macip_acl_interface_list_details(am, q, sw_if_index,
1884                                                 am->macip_acl_by_sw_if_index[sw_if_index],
1885                                                 mp->context);
1886         }
1887     }
1888 }
1889
1890 /* Set up the API message handling tables */
1891 static clib_error_t *
1892 acl_plugin_api_hookup (vlib_main_t * vm)
1893 {
1894   acl_main_t *am = &acl_main;
1895 #define _(N,n)                                                  \
1896     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
1897                            #n,                                  \
1898                            vl_api_##n##_t_handler,              \
1899                            vl_noop_handler,                     \
1900                            vl_api_##n##_t_endian,               \
1901                            vl_api_##n##_t_print,                \
1902                            sizeof(vl_api_##n##_t), 1);
1903   foreach_acl_plugin_api_msg;
1904 #undef _
1905
1906   return 0;
1907 }
1908
1909 #define vl_msg_name_crc_list
1910 #include <acl/acl_all_api_h.h>
1911 #undef vl_msg_name_crc_list
1912
1913 static void
1914 setup_message_id_table (acl_main_t * am, api_main_t * apim)
1915 {
1916 #define _(id,n,crc) \
1917   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
1918   foreach_vl_msg_name_crc_acl;
1919 #undef _
1920 }
1921
1922 static void
1923 acl_setup_fa_nodes (void)
1924 {
1925   vlib_main_t *vm = vlib_get_main ();
1926   acl_main_t *am = &acl_main;
1927   vlib_node_t *n, *n4, *n6;
1928
1929   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1930   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
1931   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
1932
1933
1934   am->l2_input_classify_next_acl_ip4 =
1935     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1936   am->l2_input_classify_next_acl_ip6 =
1937     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1938
1939   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
1940                                l2input_get_feat_names (),
1941                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
1942
1943   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
1944                                l2input_get_feat_names (),
1945                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
1946
1947
1948   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1949   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
1950   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
1951
1952   am->l2_output_classify_next_acl_ip4 =
1953     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1954   am->l2_output_classify_next_acl_ip6 =
1955     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1956
1957   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
1958                                l2output_get_feat_names (),
1959                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
1960
1961   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
1962                                l2output_get_feat_names (),
1963                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
1964 }
1965
1966 static void
1967 acl_set_timeout_sec(int timeout_type, u32 value)
1968 {
1969   acl_main_t *am = &acl_main;
1970   clib_time_t *ct = &am->vlib_main->clib_time;
1971
1972   if (timeout_type < ACL_N_TIMEOUTS) {
1973     am->session_timeout_sec[timeout_type] = value;
1974   } else {
1975     clib_warning("Unknown timeout type %d", timeout_type);
1976     return;
1977   }
1978   am->session_timeout[timeout_type] = (u64)(((f64)value)/ct->seconds_per_clock);
1979 }
1980
1981 static void
1982 acl_set_session_max_entries(u32 value)
1983 {
1984   acl_main_t *am = &acl_main;
1985   am->fa_conn_table_max_entries = value;
1986 }
1987
1988 static int
1989 acl_set_skip_ipv6_eh(u32 eh, u32 value)
1990 {
1991   acl_main_t *am = &acl_main;
1992
1993   if ((eh < 256) && (value < 2))
1994     {
1995       am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, eh, value);
1996       return 1;
1997     }
1998   else
1999     return 0;
2000 }
2001
2002
2003 static clib_error_t *
2004 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
2005 {
2006   acl_main_t *am = &acl_main;
2007   if (0 == am->acl_mheap) {
2008     /* ACL heap is not initialized, so definitely nothing to do. */
2009     return 0;
2010   }
2011   if (0 == is_add) {
2012     vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2013                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, sw_if_index);
2014     /* also unapply any ACLs in case the users did not do so. */
2015     macip_acl_interface_del_acl(am, sw_if_index);
2016     acl_interface_reset_inout_acls (sw_if_index, 0);
2017     acl_interface_reset_inout_acls (sw_if_index, 1);
2018   }
2019   return 0;
2020 }
2021
2022 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
2023
2024
2025
2026 static clib_error_t *
2027 acl_set_aclplugin_fn (vlib_main_t * vm,
2028                               unformat_input_t * input,
2029                               vlib_cli_command_t * cmd)
2030 {
2031   clib_error_t *error = 0;
2032   u32 timeout = 0;
2033   u32 val = 0;
2034   u32 eh_val = 0;
2035   uword memory_size = 0;
2036   acl_main_t *am = &acl_main;
2037
2038   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val)) {
2039     if(!acl_set_skip_ipv6_eh(eh_val, val)) {
2040       error = clib_error_return(0, "expecting eh=0..255, value=0..1");
2041     }
2042     goto done;
2043   }
2044   if (unformat (input, "use-hash-acl-matching %u", &val))
2045     {
2046       am->use_hash_acl_matching = (val !=0);
2047       goto done;
2048     }
2049   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
2050     {
2051       am->l4_match_nonfirst_fragment = (val != 0);
2052       goto done;
2053     }
2054   if (unformat (input, "heap"))
2055     {
2056       if (unformat(input, "main"))
2057         {
2058           if (unformat(input, "validate %u", &val))
2059             acl_plugin_acl_set_validate_heap(am, val);
2060           else if (unformat(input, "trace %u", &val))
2061             acl_plugin_acl_set_trace_heap(am, val);
2062           goto done;
2063         }
2064       else if (unformat(input, "hash"))
2065         {
2066           if (unformat(input, "validate %u", &val))
2067             acl_plugin_hash_acl_set_validate_heap(am, val);
2068           else if (unformat(input, "trace %u", &val))
2069             acl_plugin_hash_acl_set_trace_heap(am, val);
2070           goto done;
2071         }
2072       goto done;
2073     }
2074   if (unformat (input, "session")) {
2075     if (unformat (input, "table")) {
2076       /* The commands here are for tuning/testing. No user-serviceable parts inside */
2077       if (unformat (input, "max-entries")) {
2078         if (!unformat(input, "%u", &val)) {
2079           error = clib_error_return(0,
2080                                     "expecting maximum number of entries, got `%U`",
2081                                     format_unformat_error, input);
2082           goto done;
2083         } else {
2084           acl_set_session_max_entries(val);
2085           goto done;
2086         }
2087       }
2088       if (unformat (input, "hash-table-buckets")) {
2089         if (!unformat(input, "%u", &val)) {
2090           error = clib_error_return(0,
2091                                     "expecting maximum number of hash table buckets, got `%U`",
2092                                     format_unformat_error, input);
2093           goto done;
2094         } else {
2095           am->fa_conn_table_hash_num_buckets = val;
2096           goto done;
2097         }
2098       }
2099       if (unformat (input, "hash-table-memory")) {
2100         if (!unformat(input, "%U", unformat_memory_size, &memory_size)) {
2101           error = clib_error_return(0,
2102                                     "expecting maximum amount of hash table memory, got `%U`",
2103                                     format_unformat_error, input);
2104           goto done;
2105         } else {
2106           am->fa_conn_table_hash_memory_size = memory_size;
2107           goto done;
2108         }
2109       }
2110       goto done;
2111     }
2112     if (unformat (input, "timeout")) {
2113       if (unformat(input, "udp")) {
2114         if(unformat(input, "idle")) {
2115           if (!unformat(input, "%u", &timeout)) {
2116             error = clib_error_return(0,
2117                                       "expecting timeout value in seconds, got `%U`",
2118                                       format_unformat_error, input);
2119             goto done;
2120           } else {
2121             acl_set_timeout_sec(ACL_TIMEOUT_UDP_IDLE, timeout);
2122             goto done;
2123           }
2124         }
2125       }
2126       if (unformat(input, "tcp")) {
2127         if(unformat(input, "idle")) {
2128           if (!unformat(input, "%u", &timeout)) {
2129             error = clib_error_return(0,
2130                                       "expecting timeout value in seconds, got `%U`",
2131                                       format_unformat_error, input);
2132             goto done;
2133           } else {
2134             acl_set_timeout_sec(ACL_TIMEOUT_TCP_IDLE, timeout);
2135             goto done;
2136           }
2137         }
2138         if(unformat(input, "transient")) {
2139           if (!unformat(input, "%u", &timeout)) {
2140             error = clib_error_return(0,
2141                                       "expecting timeout value in seconds, got `%U`",
2142                                       format_unformat_error, input);
2143             goto done;
2144           } else {
2145             acl_set_timeout_sec(ACL_TIMEOUT_TCP_TRANSIENT, timeout);
2146             goto done;
2147           }
2148         }
2149       }
2150       goto done;
2151     }
2152   }
2153 done:
2154   return error;
2155 }
2156
2157 static u8 *
2158 my_format_mac_address (u8 * s, va_list * args)
2159 {
2160   u8 *a = va_arg (*args, u8 *);
2161   return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
2162                  a[0], a[1], a[2], a[3], a[4], a[5]);
2163 }
2164
2165 static inline u8 *
2166 my_macip_acl_rule_t_pretty_format (u8 *out, va_list *args)
2167 {
2168   macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
2169
2170   out = format(out, "%s action %d ip %U/%d mac %U mask %U",
2171                      a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
2172                      format_ip46_address, &a->src_ip_addr, IP46_TYPE_ANY,
2173                      a->src_prefixlen,
2174                      my_format_mac_address, a->src_mac,
2175                      my_format_mac_address, a->src_mac_mask);
2176   return(out);
2177 }
2178
2179 static void
2180 macip_acl_print(acl_main_t *am, u32 macip_acl_index)
2181 {
2182   vlib_main_t * vm = am->vlib_main;
2183   int i;
2184
2185   /* Don't try to print someone else's memory */
2186   if (macip_acl_index > vec_len(am->macip_acls))
2187     return;
2188
2189   macip_acl_list_t *a = vec_elt_at_index(am->macip_acls, macip_acl_index);
2190   int free_pool_slot = pool_is_free_index(am->macip_acls, macip_acl_index);
2191
2192   vlib_cli_output(vm, "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
2193                   macip_acl_index, a->count, vec_len(a->rules), a->tag, free_pool_slot);
2194   vlib_cli_output(vm, "  ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
2195                   a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
2196   for(i=0; i<vec_len(a->rules); i++)
2197     vlib_cli_output(vm, "    rule %d: %U\n", i, my_macip_acl_rule_t_pretty_format,
2198                     vec_elt_at_index(a->rules, i));
2199
2200 }
2201
2202 static clib_error_t *
2203 acl_show_aclplugin_macip_fn (vlib_main_t * vm,
2204                               unformat_input_t * input,
2205                               vlib_cli_command_t * cmd)
2206 {
2207   clib_error_t *error = 0;
2208   acl_main_t *am = &acl_main;
2209   int i;
2210   if (unformat (input, "interface"))
2211     {
2212       for(i=0; i < vec_len(am->macip_acl_by_sw_if_index); i++)
2213         {
2214           vlib_cli_output(vm, "  sw_if_index %d: %d\n", i, vec_elt(am->macip_acl_by_sw_if_index, i));
2215         }
2216     }
2217   else if (unformat (input, "acl"))
2218     {
2219       for(i=0; i < vec_len(am->macip_acls); i++)
2220         macip_acl_print(am, i);
2221     }
2222   return error;
2223 }
2224
2225
2226 static clib_error_t *
2227 acl_show_aclplugin_fn (vlib_main_t * vm,
2228                               unformat_input_t * input,
2229                               vlib_cli_command_t * cmd)
2230 {
2231   clib_error_t *error = 0;
2232   acl_main_t *am = &acl_main;
2233   vnet_interface_main_t *im = &am->vnet_main->interface_main;
2234   u32 *pj;
2235
2236   vnet_sw_interface_t *swif;
2237
2238   if (unformat (input, "sessions"))
2239     {
2240       u8 * out0 = format(0, "");
2241       u16 wk;
2242       u32 show_bihash_verbose = 0;
2243       u32 show_session_thread_id = ~0;
2244       u32 show_session_session_index = ~0;
2245       unformat (input, "thread %u index %u", &show_session_thread_id, &show_session_session_index);
2246       unformat (input, "verbose %u", &show_bihash_verbose);
2247       {
2248         u64 n_adds = am->fa_session_total_adds;
2249         u64 n_dels = am->fa_session_total_dels;
2250         out0 = format(out0, "Sessions total: add %lu - del %lu = %lu\n", n_adds, n_dels, n_adds - n_dels);
2251       }
2252       out0 = format(out0, "\n\nPer-thread data:\n");
2253       for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2254         acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2255         out0 = format(out0, "Thread #%d:\n", wk);
2256         if (show_session_thread_id == wk && show_session_session_index < pool_len(pw->fa_sessions_pool)) {
2257           out0 = format(out0, "  session index %u:\n", show_session_session_index);
2258           fa_session_t *sess = pw->fa_sessions_pool + show_session_session_index;
2259           u64 *m =  (u64 *)&sess->info;
2260           out0 = format(out0, "    info: %016llx %016llx %016llx %016llx %016llx %016llx\n", m[0], m[1], m[2], m[3], m[4], m[5]);
2261           out0 = format(out0, "    sw_if_index: %u\n", sess->sw_if_index);
2262           out0 = format(out0, "    tcp_flags_seen: %x\n", sess->tcp_flags_seen.as_u16);
2263           out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2264           out0 = format(out0, "    thread index: %u\n", sess->thread_index);
2265           out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2266           out0 = format(out0, "    link next index: %u\n", sess->link_next_idx);
2267           out0 = format(out0, "    link prev index: %u\n", sess->link_prev_idx);
2268           out0 = format(out0, "    link list id: %u\n", sess->link_list_id);
2269         }
2270         out0 = format(out0, "  connection add/del stats:\n", wk);
2271         pool_foreach (swif, im->sw_interfaces,
2272         ({
2273           u32 sw_if_index =  swif->sw_if_index;
2274           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;
2275           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;
2276           out0 = format(out0, "    sw_if_index %d: add %lu - del %lu = %lu\n", sw_if_index, n_adds, n_dels, n_adds - n_dels);
2277         }));
2278
2279         out0 = format(out0, "  connection timeout type lists:\n", wk);
2280         u8 tt = 0;
2281         for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2282           u32 head_session_index = pw->fa_conn_list_head[tt];
2283           out0 = format(out0, "  fa_conn_list_head[%d]: %d\n", tt, head_session_index);
2284           if (~0 != head_session_index) {
2285             fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
2286             out0 = format(out0, "    last active time: %lu\n", sess->last_active_time);
2287             out0 = format(out0, "    link enqueue time: %lu\n", sess->link_enqueue_time);
2288           }
2289         }
2290
2291         out0 = format(out0, "  Next expiry time: %lu\n", pw->next_expiry_time);
2292         out0 = format(out0, "  Requeue until time: %lu\n", pw->requeue_until_time);
2293         out0 = format(out0, "  Current time wait interval: %lu\n", pw->current_time_wait_interval);
2294         out0 = format(out0, "  Count of deleted sessions: %lu\n", pw->cnt_deleted_sessions);
2295         out0 = format(out0, "  Delete already deleted: %lu\n", pw->cnt_already_deleted_sessions);
2296         out0 = format(out0, "  Session timers restarted: %lu\n", pw->cnt_session_timer_restarted);
2297         out0 = format(out0, "  Swipe until this time: %lu\n", pw->swipe_end_time);
2298         out0 = format(out0, "  sw_if_index serviced bitmap: %U\n", format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
2299         out0 = format(out0, "  pending clear intfc bitmap : %U\n", format_bitmap_hex, pw->pending_clear_sw_if_index_bitmap);
2300         out0 = format(out0, "  clear in progress: %u\n", pw->clear_in_process);
2301         out0 = format(out0, "  interrupt is pending: %d\n", pw->interrupt_is_pending);
2302         out0 = format(out0, "  interrupt is needed: %d\n", pw->interrupt_is_needed);
2303         out0 = format(out0, "  interrupt is unwanted: %d\n", pw->interrupt_is_unwanted);
2304         out0 = format(out0, "  interrupt generation: %d\n", pw->interrupt_generation);
2305       }
2306       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
2307 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
2308       foreach_fa_cleaner_counter;
2309 #undef _
2310       vec_terminate_c_string(out0);
2311       vlib_cli_output(vm, "\n\n%s\n\n", out0);
2312       vlib_cli_output(vm, "Interrupt generation: %d\n", am->fa_interrupt_generation);
2313       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
2314               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
2315               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);
2316
2317       vec_free(out0);
2318       show_fa_sessions_hash(vm, show_bihash_verbose);
2319     }
2320   else if (unformat (input, "interface"))
2321     {
2322       u32 sw_if_index = ~0;
2323       u32 swi;
2324       u8 * out0 = format(0, "");
2325       unformat (input, "sw_if_index %u", &sw_if_index);
2326       for(swi = 0; (swi < vec_len(am->input_acl_vec_by_sw_if_index)) ||
2327                    (swi < vec_len(am->output_acl_vec_by_sw_if_index)); swi++) {
2328         out0 = format(out0, "sw_if_index %d:\n", swi);
2329
2330         if ((swi < vec_len(am->input_acl_vec_by_sw_if_index)) &&
2331             (vec_len(am->input_acl_vec_by_sw_if_index[swi]) > 0)) {
2332           out0 = format(out0, "  input acl(s): ");
2333           vec_foreach(pj, am->input_acl_vec_by_sw_if_index[swi]) {
2334             out0 = format(out0, "%d ", *pj);
2335           }
2336           out0 = format(out0, "\n");
2337         }
2338
2339         if ((swi < vec_len(am->output_acl_vec_by_sw_if_index)) &&
2340             (vec_len(am->output_acl_vec_by_sw_if_index[swi]) > 0)) {
2341           out0 = format(out0, "  output acl(s): ");
2342           vec_foreach(pj, am->output_acl_vec_by_sw_if_index[swi]) {
2343             out0 = format(out0, "%d ", *pj);
2344           }
2345           out0 = format(out0, "\n");
2346         }
2347
2348       }
2349       vec_terminate_c_string(out0);
2350       vlib_cli_output(vm, "\n%s\n", out0);
2351       vec_free(out0);
2352     }
2353   else if (unformat (input, "acl"))
2354     {
2355       u32 acl_index = ~0;
2356       u32 i;
2357       u8 * out0 = format(0, "");
2358       unformat (input, "index %u", &acl_index);
2359       for(i=0; i<vec_len(am->acls); i++) {
2360         if (acl_is_not_defined(am, i)) {
2361           /* don't attempt to show the ACLs that do not exist */
2362           continue;
2363         }
2364         if ((acl_index != ~0) && (acl_index != i)) {
2365           continue;
2366         }
2367         out0 = format(out0, "acl-index %u count %u tag {%s}\n", i, am->acls[i].count, am->acls[i].tag);
2368         acl_rule_t *r;
2369         int j;
2370         for(j=0; j<am->acls[i].count; j++) {
2371           r = &am->acls[i].rules[j];
2372           out0 = format(out0, "  %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
2373           out0 = format_acl_action(out0, r->is_permit);
2374           out0 = format(out0, " src %U/%d", format_ip46_address, &r->src, IP46_TYPE_ANY, r->src_prefixlen);
2375           out0 = format(out0, " dst %U/%d", format_ip46_address, &r->dst, IP46_TYPE_ANY, r->dst_prefixlen);
2376           out0 = format(out0, " proto %d", r->proto);
2377           out0 = format(out0, " sport %d", r->src_port_or_type_first);
2378           if (r->src_port_or_type_first != r->src_port_or_type_last) {
2379             out0 = format(out0, "-%d", r->src_port_or_type_last);
2380           }
2381           out0 = format(out0, " dport %d", r->dst_port_or_code_first);
2382           if (r->dst_port_or_code_first != r->dst_port_or_code_last) {
2383             out0 = format(out0, "-%d", r->dst_port_or_code_last);
2384           }
2385           if (r->tcp_flags_mask || r->tcp_flags_value) {
2386             out0 = format(out0, " tcpflags %d mask %d", r->tcp_flags_value, r->tcp_flags_mask);
2387           }
2388           out0 = format(out0, "\n");
2389         }
2390
2391         if (i<vec_len(am->input_sw_if_index_vec_by_acl)) {
2392           out0 = format(out0, "  applied inbound on sw_if_index: ");
2393           vec_foreach(pj, am->input_sw_if_index_vec_by_acl[i]) {
2394             out0 = format(out0, "%d ", *pj);
2395           }
2396           out0 = format(out0, "\n");
2397         }
2398         if (i<vec_len(am->output_sw_if_index_vec_by_acl)) {
2399           out0 = format(out0, "  applied outbound on sw_if_index: ");
2400           vec_foreach(pj, am->output_sw_if_index_vec_by_acl[i]) {
2401             out0 = format(out0, "%d ", *pj);
2402           }
2403           out0 = format(out0, "\n");
2404         }
2405       }
2406       vec_terminate_c_string(out0);
2407       vlib_cli_output(vm, "\n%s\n", out0);
2408       vec_free(out0);
2409     }
2410   else if (unformat (input, "memory"))
2411     {
2412       vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
2413       if (am->acl_mheap) {
2414         vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
2415       } else {
2416         vlib_cli_output (vm, " Not initialized\n");
2417       }
2418       vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
2419       if (am->hash_lookup_mheap) {
2420         vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
2421       } else {
2422         vlib_cli_output (vm, " Not initialized\n");
2423       }
2424     }
2425   else if (unformat (input, "tables"))
2426     {
2427       ace_mask_type_entry_t *mte;
2428       u32 acl_index = ~0;
2429       u32 sw_if_index = ~0;
2430       int show_acl_hash_info = 0;
2431       int show_applied_info = 0;
2432       int show_mask_type = 0;
2433       int show_bihash = 0;
2434       u32 show_bihash_verbose = 0;
2435
2436       if (unformat (input, "acl")) {
2437         show_acl_hash_info = 1;
2438         /* mask-type is handy to see as well right there */
2439         show_mask_type = 1;
2440         unformat (input, "index %u", &acl_index);
2441       } else if (unformat (input, "applied")) {
2442         show_applied_info = 1;
2443         unformat (input, "sw_if_index %u", &sw_if_index);
2444       } else if (unformat (input, "mask")) {
2445         show_mask_type = 1;
2446       } else if (unformat (input, "hash")) {
2447         show_bihash = 1;
2448         unformat (input, "verbose %u", &show_bihash_verbose);
2449       }
2450
2451       if ( ! (show_mask_type || show_acl_hash_info || show_applied_info || show_bihash) ) {
2452         /* if no qualifiers specified, show all */
2453         show_mask_type = 1;
2454         show_acl_hash_info = 1;
2455         show_applied_info = 1;
2456         show_bihash = 1;
2457       }
2458
2459       if (show_mask_type) {
2460         vlib_cli_output(vm, "Mask-type entries:");
2461         /* *INDENT-OFF* */
2462         pool_foreach(mte, am->ace_mask_type_pool,
2463         ({
2464           vlib_cli_output(vm, "     %3d: %016llx %016llx %016llx %016llx %016llx %016llx  refcount %d",
2465                         mte - am->ace_mask_type_pool,
2466                         mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
2467                         mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
2468         }));
2469         /* *INDENT-ON* */
2470       }
2471
2472       if (show_acl_hash_info) {
2473         u32 i,j;
2474         u8 * out0 = format(0, "");
2475         u64 *m;
2476         out0 = format(out0, "Mask-ready ACL representations\n");
2477         for (i=0; i< vec_len(am->hash_acl_infos); i++) {
2478           if ((acl_index != ~0) && (acl_index != i)) {
2479             continue;
2480           }
2481           hash_acl_info_t *ha = &am->hash_acl_infos[i];
2482           out0 = format(out0, "acl-index %u bitmask-ready layout\n", i);
2483           out0 = format(out0, "  applied  inbound on sw_if_index list: %U\n", format_vec32, ha->inbound_sw_if_index_list, "%d");
2484           out0 = format(out0, "  applied outbound on sw_if_index list: %U\n", format_vec32, ha->outbound_sw_if_index_list, "%d");
2485           out0 = format(out0, "  mask type index bitmap: %U\n", format_bitmap_hex, ha->mask_type_index_bitmap);
2486           for(j=0; j<vec_len(ha->rules); j++) {
2487             hash_ace_info_t *pa = &ha->rules[j];
2488             m = (u64 *)&pa->match;
2489             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",
2490                                 j, m[0], m[1], m[2], m[3], m[4], m[5], pa->mask_type_index,
2491                                 pa->acl_index, pa->ace_index, pa->action,
2492                                 pa->src_portrange_not_powerof2, pa->dst_portrange_not_powerof2);
2493           }
2494         }
2495         vec_terminate_c_string(out0);
2496         vlib_cli_output(vm, "\n%s\n", out0);
2497         vec_free(out0);
2498       }
2499
2500       if (show_applied_info) {
2501         u32 swi, j;
2502         u8 * out0 = format(0, "");
2503         out0 = format(out0, "Applied lookup entries for interfaces\n");
2504
2505         for(swi = 0; (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) ||
2506                    (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) ||
2507                    (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) ||
2508                    (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)); swi++) {
2509           if ((sw_if_index != ~0) && (sw_if_index != swi)) {
2510             continue;
2511           }
2512           out0 = format(out0, "sw_if_index %d:\n", swi);
2513           if (swi < vec_len(am->input_applied_hash_acl_info_by_sw_if_index)) {
2514             applied_hash_acl_info_t *pal = &am->input_applied_hash_acl_info_by_sw_if_index[swi];
2515             out0 = format(out0, "  input lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2516             out0 = format(out0, "  input applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2517           }
2518           if (swi < vec_len(am->input_hash_entry_vec_by_sw_if_index)) {
2519             out0 = format(out0, "  input lookup applied entries:\n");
2520             for(j=0; j<vec_len(am->input_hash_entry_vec_by_sw_if_index[swi]); j++) {
2521               applied_hash_ace_entry_t *pae = &am->input_hash_entry_vec_by_sw_if_index[swi][j];
2522               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
2523                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2524                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
2525             }
2526           }
2527
2528           if (swi < vec_len(am->output_applied_hash_acl_info_by_sw_if_index)) {
2529             applied_hash_acl_info_t *pal = &am->output_applied_hash_acl_info_by_sw_if_index[swi];
2530             out0 = format(out0, "  output lookup mask_type_index_bitmap: %U\n", format_bitmap_hex, pal->mask_type_index_bitmap);
2531             out0 = format(out0, "  output applied acls: %U\n", format_vec32, pal->applied_acls, "%d");
2532           }
2533           if (swi < vec_len(am->output_hash_entry_vec_by_sw_if_index)) {
2534             out0 = format(out0, "  output lookup applied entries:\n");
2535             for(j=0; j<vec_len(am->output_hash_entry_vec_by_sw_if_index[swi]); j++) {
2536               applied_hash_ace_entry_t *pae = &am->output_hash_entry_vec_by_sw_if_index[swi][j];
2537               out0 = format(out0, "    %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld\n",
2538                                        j, pae->acl_index, pae->ace_index, pae->action, pae->hash_ace_info_index,
2539                                        pae->next_applied_entry_index, pae->prev_applied_entry_index, pae->tail_applied_entry_index, pae->hitcount);
2540             }
2541           }
2542
2543         }
2544         vec_terminate_c_string(out0);
2545         vlib_cli_output(vm, "\n%s\n", out0);
2546         vec_free(out0);
2547       }
2548
2549       if (show_bihash) {
2550         show_hash_acl_hash(vm, am, show_bihash_verbose);
2551       }
2552     }
2553   return error;
2554 }
2555
2556 static clib_error_t *
2557 acl_clear_aclplugin_fn (vlib_main_t * vm,
2558                               unformat_input_t * input,
2559                               vlib_cli_command_t * cmd)
2560 {
2561   clib_error_t *error = 0;
2562   acl_main_t *am = &acl_main;
2563   vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2564                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
2565   return error;
2566 }
2567
2568  /* *INDENT-OFF* */
2569 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
2570     .path = "set acl-plugin",
2571     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
2572     .function = acl_set_aclplugin_fn,
2573 };
2574
2575 VLIB_CLI_COMMAND (aclplugin_show_command, static) = {
2576     .path = "show acl-plugin",
2577     .short_help = "show acl-plugin {sessions|acl|interface|tables}",
2578     .function = acl_show_aclplugin_fn,
2579 };
2580
2581 VLIB_CLI_COMMAND (aclplugin_show_macip_command, static) = {
2582     .path = "show acl-plugin macip",
2583     .short_help = "show acl-plugin macip {acl|interface}",
2584     .function = acl_show_aclplugin_macip_fn,
2585 };
2586
2587
2588 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
2589     .path = "clear acl-plugin sessions",
2590     .short_help = "clear acl-plugin sessions",
2591     .function = acl_clear_aclplugin_fn,
2592 };
2593 /* *INDENT-ON* */
2594
2595 static clib_error_t *
2596 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
2597 {
2598   acl_main_t *am = &acl_main;
2599   u32 conn_table_hash_buckets;
2600   u32 conn_table_hash_memory_size;
2601   u32 conn_table_max_entries;
2602   u32 main_heap_size;
2603   u32 hash_heap_size;
2604   u32 hash_lookup_hash_buckets;
2605   u32 hash_lookup_hash_memory;
2606
2607   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2608     {
2609       if (unformat (input, "connection hash buckets %d", &conn_table_hash_buckets))
2610         am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
2611       else if (unformat (input, "connection hash memory %d",
2612                          &conn_table_hash_memory_size))
2613         am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
2614       else if (unformat (input, "connection count max %d",
2615                          &conn_table_max_entries))
2616         am->fa_conn_table_max_entries = conn_table_max_entries;
2617       else if (unformat (input, "main heap size %d",
2618                          &main_heap_size))
2619         am->acl_mheap_size = main_heap_size;
2620       else if (unformat (input, "hash lookup heap size %d",
2621                          &hash_heap_size))
2622         am->hash_lookup_mheap_size = hash_heap_size;
2623       else if (unformat (input, "hash lookup hash buckets %d",
2624                          &hash_lookup_hash_buckets))
2625         am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
2626       else if (unformat (input, "hash lookup hash memory %d",
2627                          &hash_lookup_hash_memory))
2628         am->hash_lookup_hash_memory = hash_lookup_hash_memory;
2629       else
2630         return clib_error_return (0, "unknown input '%U'",
2631                                   format_unformat_error, input);
2632     }
2633   return 0;
2634 }
2635 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
2636
2637 static clib_error_t *
2638 acl_init (vlib_main_t * vm)
2639 {
2640   acl_main_t *am = &acl_main;
2641   clib_error_t *error = 0;
2642   memset (am, 0, sizeof (*am));
2643   am->vlib_main = vm;
2644   am->vnet_main = vnet_get_main ();
2645
2646   u8 *name = format (0, "acl_%08x%c", api_version, 0);
2647
2648   /* Ask for a correctly-sized block of API message decode slots */
2649   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
2650                                             VL_MSG_FIRST_AVAILABLE);
2651
2652   error = acl_plugin_api_hookup (vm);
2653
2654  /* Add our API messages to the global name_crc hash table */
2655   setup_message_id_table (am, &api_main);
2656
2657   vec_free (name);
2658
2659   acl_setup_fa_nodes();
2660
2661   am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
2662   am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
2663
2664   am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
2665   am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
2666
2667   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
2668   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
2669   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;
2670
2671   am->fa_conn_table_hash_num_buckets = ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
2672   am->fa_conn_table_hash_memory_size = ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
2673   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
2674   vlib_thread_main_t *tm = vlib_get_thread_main ();
2675   vec_validate(am->per_worker_data, tm->n_vlib_mains-1);
2676   {
2677     u16 wk;
2678     u8 tt;
2679     for (wk = 0; wk < vec_len (am->per_worker_data); wk++) {
2680       acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
2681       vec_validate(pw->fa_conn_list_head, ACL_N_TIMEOUTS-1);
2682       vec_validate(pw->fa_conn_list_tail, ACL_N_TIMEOUTS-1);
2683       for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
2684         pw->fa_conn_list_head[tt] = ~0;
2685         pw->fa_conn_list_tail[tt] = ~0;
2686       }
2687     }
2688   }
2689
2690   am->fa_min_deleted_sessions_per_interval = ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
2691   am->fa_max_deleted_sessions_per_interval = ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
2692   am->fa_cleaner_wait_time_increment = ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
2693
2694   am->fa_cleaner_cnt_delete_by_sw_index = 0;
2695   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
2696   am->fa_cleaner_cnt_unknown_event = 0;
2697   am->fa_cleaner_cnt_timer_restarted = 0;
2698   am->fa_cleaner_cnt_wait_with_timeout = 0;
2699
2700
2701 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
2702   foreach_acl_eh
2703 #undef _
2704
2705   am->l4_match_nonfirst_fragment = 1;
2706
2707   /* use the new fancy hash-based matching */
2708   am->use_hash_acl_matching = 1;
2709
2710   return error;
2711 }
2712
2713 VLIB_INIT_FUNCTION (acl_init);