Clean up old datapath code in ACL plugin.
[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
56 acl_main_t acl_main;
57
58 #define REPLY_MSG_ID_BASE am->msg_id_base
59 #include <vlibapi/api_helper_macros.h>
60
61 /* List of message types that this plugin understands */
62
63 #define foreach_acl_plugin_api_msg              \
64 _(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \
65 _(ACL_ADD_REPLACE, acl_add_replace)                             \
66 _(ACL_DEL, acl_del)                             \
67 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
68 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list)       \
69 _(ACL_DUMP, acl_dump)  \
70 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
71 _(MACIP_ACL_ADD, macip_acl_add) \
72 _(MACIP_ACL_DEL, macip_acl_del) \
73 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
74 _(MACIP_ACL_DUMP, macip_acl_dump) \
75 _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get)
76
77 /* *INDENT-OFF* */
78 VLIB_PLUGIN_REGISTER () = {
79     .version = VPP_BUILD_VER,
80     .description = "Access Control Lists",
81 };
82 /* *INDENT-ON* */
83
84 static void
85 vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
86 {
87   acl_main_t *am = &acl_main;
88   vl_api_acl_plugin_get_version_reply_t *rmp;
89   int msg_size = sizeof (*rmp);
90   unix_shared_memory_queue_t *q;
91
92   q = vl_api_client_index_to_input_queue (mp->client_index);
93   if (q == 0)
94     {
95       return;
96     }
97
98   rmp = vl_msg_api_alloc (msg_size);
99   memset (rmp, 0, msg_size);
100   rmp->_vl_msg_id =
101     ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
102   rmp->context = mp->context;
103   rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
104   rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
105
106   vl_msg_api_send_shmem (q, (u8 *) & rmp);
107 }
108
109
110 static int
111 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
112               u32 * acl_list_index, u8 * tag)
113 {
114   acl_main_t *am = &acl_main;
115   acl_list_t *a;
116   acl_rule_t *r;
117   acl_rule_t *acl_new_rules;
118   int i;
119
120   if (*acl_list_index != ~0)
121     {
122       /* They supplied some number, let's see if this ACL exists */
123       if (pool_is_free_index (am->acls, *acl_list_index))
124         {
125           /* tried to replace a non-existent ACL, no point doing anything */
126           return -1;
127         }
128     }
129
130   /* Create and populate the rules */
131   acl_new_rules = clib_mem_alloc_aligned (sizeof (acl_rule_t) * count,
132                                           CLIB_CACHE_LINE_BYTES);
133   if (!acl_new_rules)
134     {
135       /* Could not allocate rules. New or existing ACL - bail out regardless */
136       return -1;
137     }
138
139   for (i = 0; i < count; i++)
140     {
141       r = &acl_new_rules[i];
142       r->is_permit = rules[i].is_permit;
143       r->is_ipv6 = rules[i].is_ipv6;
144       if (r->is_ipv6)
145         {
146           memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src));
147           memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst));
148         }
149       else
150         {
151           memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4));
152           memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4));
153         }
154       r->src_prefixlen = rules[i].src_ip_prefix_len;
155       r->dst_prefixlen = rules[i].dst_ip_prefix_len;
156       r->proto = rules[i].proto;
157       r->src_port_or_type_first = ntohs ( rules[i].srcport_or_icmptype_first );
158       r->src_port_or_type_last = ntohs ( rules[i].srcport_or_icmptype_last );
159       r->dst_port_or_code_first = ntohs ( rules[i].dstport_or_icmpcode_first );
160       r->dst_port_or_code_last = ntohs ( rules[i].dstport_or_icmpcode_last );
161       r->tcp_flags_value = rules[i].tcp_flags_value;
162       r->tcp_flags_mask = rules[i].tcp_flags_mask;
163     }
164
165   if (~0 == *acl_list_index)
166     {
167       /* Get ACL index */
168       pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
169       memset (a, 0, sizeof (*a));
170       /* Will return the newly allocated ACL index */
171       *acl_list_index = a - am->acls;
172     }
173   else
174     {
175       a = am->acls + *acl_list_index;
176       /* Get rid of the old rules */
177       clib_mem_free (a->rules);
178     }
179   a->rules = acl_new_rules;
180   a->count = count;
181   memcpy (a->tag, tag, sizeof (a->tag));
182
183   return 0;
184 }
185
186 static int
187 acl_del_list (u32 acl_list_index)
188 {
189   acl_main_t *am = &acl_main;
190   acl_list_t *a;
191   int i, ii;
192   if (pool_is_free_index (am->acls, acl_list_index))
193     {
194       return -1;
195     }
196
197   /* delete any references to the ACL */
198   for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++)
199     {
200       for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]);
201            /* see body */ )
202         {
203           if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii])
204             {
205               vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii);
206             }
207           else
208             {
209               ii++;
210             }
211         }
212     }
213   for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++)
214     {
215       for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]);
216            /* see body */ )
217         {
218           if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii])
219             {
220               vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii);
221             }
222           else
223             {
224               ii++;
225             }
226         }
227     }
228
229   /* now we can delete the ACL itself */
230   a = &am->acls[acl_list_index];
231   if (a->rules)
232     {
233       clib_mem_free (a->rules);
234     }
235   pool_put (am->acls, a);
236   return 0;
237 }
238
239 /* Some aids in ASCII graphing the content */
240 #define XX "\377"
241 #define __ "\000"
242 #define _(x)
243 #define v
244
245 u8 ip4_5tuple_mask[] =
246 _("             dmac               smac            etype ")
247 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
248   _("        v ihl totlen   ")
249   _(0x0000)
250   __ __ __ __
251   _("        ident fl+fo    ")
252   _(0x0004)
253   __ __ __ __
254   _("       ttl pr checksum ")
255   _(0x0008)
256   __ XX __ __
257   _("        src address    ")
258   _(0x000C)
259   XX XX XX XX
260   _("        dst address    ")
261   _(0x0010)
262   XX XX XX XX
263   _("L4 T/U  sport dport    ")
264   _(tcpudp)
265   XX XX XX XX
266   _(padpad)
267   __ __ __ __
268   _(padpad)
269   __ __ __ __
270   _(padeth)
271   __ __;
272
273      u8 ip6_5tuple_mask[] =
274        _("             dmac               smac            etype ")
275   _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
276   _("        v  tc + flow ")
277   _(0x0000) __ __ __ __
278   _("        plen  nh hl  ")
279   _(0x0004) __ __ XX __
280   _("        src address  ")
281   _(0x0008) XX XX XX XX
282   _(0x000C) XX XX XX XX
283   _(0x0010) XX XX XX XX
284   _(0x0014) XX XX XX XX
285   _("        dst address  ")
286   _(0x0018) XX XX XX XX
287   _(0x001C) XX XX XX XX
288   _(0x0020) XX XX XX XX
289   _(0x0024) XX XX XX XX
290   _("L4T/U  sport dport   ")
291   _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
292
293 #undef XX
294 #undef __
295 #undef _
296 #undef v
297
298      static int count_skip (u8 * p, u32 size)
299 {
300   u64 *p64 = (u64 *) p;
301   /* Be tolerant to null pointer */
302   if (0 == p)
303     return 0;
304
305   while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
306     {
307       p64++;
308     }
309   return (p64 - (u64 *) p) / 2;
310 }
311
312 static int
313 acl_classify_add_del_table_big (vnet_classify_main_t * cm, u8 * mask,
314                             u32 mask_len, u32 next_table_index,
315                             u32 miss_next_index, u32 * table_index,
316                             int is_add)
317 {
318   u32 nbuckets = 65536;
319   u32 memory_size = 2 << 30;
320   u32 skip = count_skip (mask, mask_len);
321   u32 match = (mask_len / 16) - skip;
322   u8 *skip_mask_ptr = mask + 16 * skip;
323   u32 current_data_flag = 0;
324   int current_data_offset = 0;
325
326   if (0 == match)
327     match = 1;
328
329   return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
330                                       memory_size, skip, match,
331                                       next_table_index, miss_next_index,
332                                       table_index, current_data_flag,
333                                       current_data_offset, is_add,
334                                       1 /* delete_chain */);
335 }
336
337 static int
338 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
339                             u32 mask_len, u32 next_table_index,
340                             u32 miss_next_index, u32 * table_index,
341                             int is_add)
342 {
343   u32 nbuckets = 32;
344   u32 memory_size = 2 << 20;
345   u32 skip = count_skip (mask, mask_len);
346   u32 match = (mask_len / 16) - skip;
347   u8 *skip_mask_ptr = mask + 16 * skip;
348   u32 current_data_flag = 0;
349   int current_data_offset = 0;
350
351   if (0 == match)
352     match = 1;
353
354   return vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
355                                       memory_size, skip, match,
356                                       next_table_index, miss_next_index,
357                                       table_index, current_data_flag,
358                                       current_data_offset, is_add,
359                                       1 /* delete_chain */);
360 }
361
362
363 static int
364 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
365 {
366   vnet_classify_main_t *cm = &vnet_classify_main;
367   u32 ip4_table_index = ~0;
368   u32 ip6_table_index = ~0;
369
370   vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
371                            sw_if_index, ~0);
372   vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
373                            sw_if_index, ~0);
374
375   vnet_l2_input_classify_enable_disable (sw_if_index, 0);
376
377   if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
378     {
379       ip4_table_index =
380         am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
381       am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
382       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
383                                   sizeof (ip4_5tuple_mask) - 1, ~0,
384                                   am->l2_input_classify_next_acl_ip4,
385                                   &ip4_table_index, 0);
386     }
387   if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
388     {
389       ip6_table_index =
390         am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
391       am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
392       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
393                                   sizeof (ip6_5tuple_mask) - 1, ~0,
394                                   am->l2_input_classify_next_acl_ip6,
395                                   &ip6_table_index, 0);
396     }
397
398   return 0;
399 }
400
401 static int
402 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
403 {
404   vnet_classify_main_t *cm = &vnet_classify_main;
405   u32 ip4_table_index = ~0;
406   u32 ip6_table_index = ~0;
407
408   vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
409                            sw_if_index, ~0);
410   vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
411                            sw_if_index, ~0);
412
413   vnet_l2_output_classify_enable_disable (sw_if_index, 0);
414
415   if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
416     {
417       ip4_table_index =
418         am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
419       am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
420       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
421                                   sizeof (ip4_5tuple_mask) - 1, ~0,
422                                   am->l2_output_classify_next_acl_ip4,
423                                   &ip4_table_index, 0);
424     }
425   if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
426     {
427       ip6_table_index =
428         am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
429       am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
430       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
431                                   sizeof (ip6_5tuple_mask) - 1, ~0,
432                                   am->l2_output_classify_next_acl_ip6,
433                                   &ip6_table_index, 0);
434     }
435
436   return 0;
437 }
438
439 static int
440 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
441 {
442   vnet_classify_main_t *cm = &vnet_classify_main;
443   u32 ip4_table_index = ~0;
444   u32 ip6_table_index = ~0;
445   int rv;
446
447   /* in case there were previous tables attached */
448   acl_unhook_l2_input_classify (am, sw_if_index);
449   rv =
450     acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
451                                 sizeof (ip4_5tuple_mask) - 1, ~0,
452                                 am->l2_input_classify_next_acl_ip4,
453                                 &ip4_table_index, 1);
454   if (rv)
455     return rv;
456   rv =
457     acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
458                                 sizeof (ip6_5tuple_mask) - 1, ~0,
459                                 am->l2_input_classify_next_acl_ip6,
460                                 &ip6_table_index, 1);
461   if (rv)
462     {
463       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
464                                   sizeof (ip4_5tuple_mask) - 1, ~0,
465                                   am->l2_input_classify_next_acl_ip4,
466                                   &ip4_table_index, 0);
467       return rv;
468     }
469   rv =
470     vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
471                                        ip6_table_index, ~0);
472   clib_warning
473     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
474      sw_if_index, ip4_table_index, ip6_table_index);
475   if (rv)
476     {
477       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
478                                   sizeof (ip6_5tuple_mask) - 1, ~0,
479                                   am->l2_input_classify_next_acl_ip6,
480                                   &ip6_table_index, 0);
481       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
482                                   sizeof (ip4_5tuple_mask) - 1, ~0,
483                                   am->l2_input_classify_next_acl_ip4,
484                                   &ip4_table_index, 0);
485       return rv;
486     }
487
488   am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
489     ip4_table_index;
490   am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
491     ip6_table_index;
492
493   vnet_l2_input_classify_enable_disable (sw_if_index, 1);
494   return rv;
495 }
496
497 static int
498 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
499 {
500   vnet_classify_main_t *cm = &vnet_classify_main;
501   u32 ip4_table_index = ~0;
502   u32 ip6_table_index = ~0;
503   int rv;
504
505   /* in case there were previous tables attached */
506   acl_unhook_l2_output_classify (am, sw_if_index);
507   rv =
508     acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
509                                 sizeof (ip4_5tuple_mask) - 1, ~0,
510                                 am->l2_output_classify_next_acl_ip4,
511                                 &ip4_table_index, 1);
512   if (rv)
513     return rv;
514   rv =
515     acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
516                                 sizeof (ip6_5tuple_mask) - 1, ~0,
517                                 am->l2_output_classify_next_acl_ip6,
518                                 &ip6_table_index, 1);
519   if (rv)
520     {
521       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
522                                   sizeof (ip4_5tuple_mask) - 1, ~0,
523                                   am->l2_output_classify_next_acl_ip4,
524                                   &ip4_table_index, 0);
525       return rv;
526     }
527   rv =
528     vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
529                                         ip6_table_index, ~0);
530   clib_warning
531     ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
532      sw_if_index, ip4_table_index, ip6_table_index);
533   if (rv)
534     {
535       acl_classify_add_del_table_big (cm, ip6_5tuple_mask,
536                                   sizeof (ip6_5tuple_mask) - 1, ~0,
537                                   am->l2_output_classify_next_acl_ip6,
538                                   &ip6_table_index, 0);
539       acl_classify_add_del_table_big (cm, ip4_5tuple_mask,
540                                   sizeof (ip4_5tuple_mask) - 1, ~0,
541                                   am->l2_output_classify_next_acl_ip4,
542                                   &ip4_table_index, 0);
543       return rv;
544     }
545
546   am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
547     ip4_table_index;
548   am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
549     ip6_table_index;
550
551   vnet_l2_output_classify_enable_disable (sw_if_index, 1);
552   return rv;
553 }
554
555
556
557 int
558 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
559                                  int enable_disable)
560 {
561   int rv;
562
563   /* Utterly wrong? */
564   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
565                           sw_if_index))
566     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
567
568   acl_fa_enable_disable(sw_if_index, 1, enable_disable);
569
570   if (enable_disable)
571     {
572       rv = acl_hook_l2_input_classify (am, sw_if_index);
573     }
574   else
575     {
576       rv = acl_unhook_l2_input_classify (am, sw_if_index);
577     }
578
579   return rv;
580 }
581
582 int
583 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
584                                   int enable_disable)
585 {
586   int rv;
587
588   /* Utterly wrong? */
589   if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
590                           sw_if_index))
591     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
592
593   acl_fa_enable_disable(sw_if_index, 0, enable_disable);
594
595   if (enable_disable)
596     {
597       rv = acl_hook_l2_output_classify (am, sw_if_index);
598     }
599   else
600     {
601       rv = acl_unhook_l2_output_classify (am, sw_if_index);
602     }
603
604   return rv;
605 }
606
607
608 static int
609 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
610 {
611   acl_main_t *am = &acl_main;
612   if (is_input)
613     {
614       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
615       vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
616                1);
617       acl_interface_in_enable_disable (am, sw_if_index, 1);
618     }
619   else
620     {
621       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
622       vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
623                &acl_list_index, 1);
624       acl_interface_out_enable_disable (am, sw_if_index, 1);
625     }
626   return 0;
627 }
628
629 static int
630 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
631 {
632   acl_main_t *am = &acl_main;
633   int i;
634   int rv = -1;
635   if (is_input)
636     {
637       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
638       for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
639            i++)
640         {
641           if (acl_list_index ==
642               am->input_acl_vec_by_sw_if_index[sw_if_index][i])
643             {
644               vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
645               rv = 0;
646               break;
647             }
648         }
649       if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
650         {
651           acl_interface_in_enable_disable (am, sw_if_index, 0);
652         }
653     }
654   else
655     {
656       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
657       for (i = 0;
658            i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
659         {
660           if (acl_list_index ==
661               am->output_acl_vec_by_sw_if_index[sw_if_index][i])
662             {
663               vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
664               rv = 0;
665               break;
666             }
667         }
668       if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
669         {
670           acl_interface_out_enable_disable (am, sw_if_index, 0);
671         }
672     }
673   return rv;
674 }
675
676 static void
677 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
678 {
679   acl_main_t *am = &acl_main;
680   if (is_input)
681     {
682       acl_interface_in_enable_disable (am, sw_if_index, 0);
683       vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
684       vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
685     }
686   else
687     {
688       acl_interface_out_enable_disable (am, sw_if_index, 0);
689       vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
690       vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
691     }
692 }
693
694 static int
695 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
696                                  u32 acl_list_index)
697 {
698   int rv = -1;
699   if (is_add)
700     {
701       rv =
702         acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
703     }
704   else
705     {
706       rv =
707         acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
708     }
709   return rv;
710 }
711
712
713 typedef struct
714 {
715   u8 is_ipv6;
716   u8 mac_mask[6];
717   u8 prefix_len;
718   u32 count;
719   u32 table_index;
720   u32 arp_table_index;
721 } macip_match_type_t;
722
723 static u32
724 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
725                        u8 is_ipv6)
726 {
727   u32 i;
728   if (mv)
729     {
730       for (i = 0; i < vec_len (mv); i++)
731         {
732           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
733               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
734             {
735               return i;
736             }
737         }
738     }
739   return ~0;
740 }
741
742
743 /* Get metric used to sort match types.
744    The more specific and the more often seen - the bigger the metric */
745 static int
746 match_type_metric (macip_match_type_t * m)
747 {
748   /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */
749   return m->prefix_len + m->is_ipv6 + 10 * m->count;
750 }
751
752 static int
753 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
754 {
755   /* Ascending sort based on the metric values */
756   return match_type_metric (m1) - match_type_metric (m2);
757 }
758
759 /* Get the offset of L3 source within ethernet packet */
760 static int
761 get_l3_src_offset(int is6)
762 {
763   if(is6)
764     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
765   else
766     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
767 }
768
769 static int
770 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
771 {
772   macip_match_type_t *mvec = NULL;
773   macip_match_type_t *mt;
774   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
775   int i;
776   u32 match_type_index;
777   u32 last_table;
778   u8 mask[5 * 16];
779   vnet_classify_main_t *cm = &vnet_classify_main;
780
781   /* Count the number of different types of rules */
782   for (i = 0; i < a->count; i++)
783     {
784       if (~0 ==
785           (match_type_index =
786            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
787                                   a->rules[i].src_prefixlen,
788                                   a->rules[i].is_ipv6)))
789         {
790           match_type_index = vec_len (mvec);
791           vec_validate (mvec, match_type_index);
792           memcpy (mvec[match_type_index].mac_mask,
793                   a->rules[match_type_index].src_mac_mask, 6);
794           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
795           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
796           mvec[match_type_index].table_index = ~0;
797         }
798       mvec[match_type_index].count++;
799     }
800   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
801   vec_sort_with_function (mvec, match_type_compare);
802   /* Create the classifier tables */
803   last_table = ~0;
804   /* First add ARP tables */
805   vec_foreach (mt, mvec)
806   {
807     int mask_len;
808     int is6 = mt->is_ipv6;
809
810     mt->arp_table_index = ~0;
811     if (!is6)
812       {
813         memset (mask, 0, sizeof (mask));
814         memcpy (&mask[6], mt->mac_mask, 6);
815         memset (&mask[12], 0xff, 2); /* ethernet protocol */
816         memcpy (&mask[14 + 8], mt->mac_mask, 6);
817
818         for (i = 0; i < (mt->prefix_len / 8); i++)
819           mask[14 + 14 + i] = 0xff;
820         if (mt->prefix_len % 8)
821           mask[14 + 14 + (mt->prefix_len / 8)] = 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
822
823         mask_len = ((14 + 14 + ((mt->prefix_len+7) / 8) +
824                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
825         acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
826                                (~0 == last_table) ? 0 : ~0, &mt->arp_table_index,
827                                1);
828         last_table = mt->arp_table_index;
829       }
830   }
831   /* Now add IP[46] tables */
832   vec_foreach (mt, mvec)
833   {
834     int mask_len;
835     int is6 = mt->is_ipv6;
836     int l3_src_offs = get_l3_src_offset(is6);
837     memset (mask, 0, sizeof (mask));
838     memcpy (&mask[6], mt->mac_mask, 6);
839     for (i = 0; i < (mt->prefix_len / 8); i++)
840       {
841         mask[l3_src_offs + i] = 0xff;
842       }
843     if (mt->prefix_len % 8)
844       {
845         mask[l3_src_offs + (mt->prefix_len / 8)] =
846           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
847       }
848     /*
849      * Round-up the number of bytes needed to store the prefix,
850      * and round up the number of vectors too
851      */
852     mask_len = ((l3_src_offs + ((mt->prefix_len+7) / 8) +
853                 (sizeof (u32x4)-1))/sizeof(u32x4)) * sizeof (u32x4);
854     acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
855                                 (~0 == last_table) ? 0 : ~0, &mt->table_index,
856                                 1);
857     last_table = mt->table_index;
858   }
859   a->ip4_table_index = ~0;
860   a->ip6_table_index = ~0;
861   a->l2_table_index = last_table;
862
863   /* Populate the classifier tables with rules from the MACIP ACL */
864   for (i = 0; i < a->count; i++)
865     {
866       u32 action = 0;
867       u32 metadata = 0;
868       int is6 = a->rules[i].is_ipv6;
869       int l3_src_offs = get_l3_src_offset(is6);
870       memset (mask, 0, sizeof (mask));
871       memcpy (&mask[6], a->rules[i].src_mac, 6);
872       memset (&mask[12], 0xff, 2); /* ethernet protocol */
873       if (is6)
874         {
875           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
876           mask[12] = 0x86;
877           mask[13] = 0xdd;
878         }
879       else
880         {
881           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
882           mask[12] = 0x08;
883           mask[13] = 0x00;
884         }
885       match_type_index =
886         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
887                                a->rules[i].src_prefixlen,
888                                a->rules[i].is_ipv6);
889       /* add session to table mvec[match_type_index].table_index; */
890       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
891                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
892                                      0, action, metadata, 1);
893       /* add ARP table entry too */
894       if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
895         {
896           memset (mask, 0, sizeof (mask));
897           memcpy (&mask[6], a->rules[i].src_mac, 6);
898           mask[12] = 0x08;
899           mask[13] = 0x06;
900           memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
901           memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
902           vnet_classify_add_del_session (cm, mvec[match_type_index].arp_table_index,
903                                     mask, a->rules[i].is_permit ? ~0 : 0, i,
904                                     0, action, metadata, 1);
905         }
906     }
907   return 0;
908 }
909
910 static void
911 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
912 {
913   vnet_classify_main_t *cm = &vnet_classify_main;
914   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
915
916   if (a->ip4_table_index != ~0)
917     {
918       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
919       a->ip4_table_index = ~0;
920     }
921   if (a->ip6_table_index != ~0)
922     {
923       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
924       a->ip6_table_index = ~0;
925     }
926   if (a->l2_table_index != ~0)
927     {
928       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
929       a->l2_table_index = ~0;
930     }
931 }
932
933 static int
934 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
935                     u32 * acl_list_index, u8 * tag)
936 {
937   acl_main_t *am = &acl_main;
938   macip_acl_list_t *a;
939   macip_acl_rule_t *r;
940   macip_acl_rule_t *acl_new_rules;
941   int i;
942
943   /* Create and populate the rules */
944   acl_new_rules = clib_mem_alloc_aligned (sizeof (macip_acl_rule_t) * count,
945                                           CLIB_CACHE_LINE_BYTES);
946   if (!acl_new_rules)
947     {
948       /* Could not allocate rules. New or existing ACL - bail out regardless */
949       return -1;
950     }
951
952   for (i = 0; i < count; i++)
953     {
954       r = &acl_new_rules[i];
955       r->is_permit = rules[i].is_permit;
956       r->is_ipv6 = rules[i].is_ipv6;
957       memcpy (&r->src_mac, rules[i].src_mac, 6);
958       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
959       if(rules[i].is_ipv6)
960         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
961       else
962         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
963       r->src_prefixlen = rules[i].src_ip_prefix_len;
964     }
965
966   /* Get ACL index */
967   pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
968   memset (a, 0, sizeof (*a));
969   /* Will return the newly allocated ACL index */
970   *acl_list_index = a - am->macip_acls;
971
972   a->rules = acl_new_rules;
973   a->count = count;
974   memcpy (a->tag, tag, sizeof (a->tag));
975
976   /* Create and populate the classifer tables */
977   macip_create_classify_tables (am, *acl_list_index);
978
979   return 0;
980 }
981
982
983 /* No check for validity of sw_if_index - the callers were supposed to validate */
984
985 static int
986 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
987 {
988   int rv;
989   u32 macip_acl_index;
990   macip_acl_list_t *a;
991   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
992   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
993   /* No point in deleting MACIP ACL which is not applied */
994   if (~0 == macip_acl_index)
995     return -1;
996   a = &am->macip_acls[macip_acl_index];
997   /* remove the classifier tables off the interface L2 ACL */
998   rv =
999     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1000                               a->ip6_table_index, a->l2_table_index, 0);
1001   /* Unset the MACIP ACL index */
1002   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1003   return rv;
1004 }
1005
1006 /* No check for validity of sw_if_index - the callers were supposed to validate */
1007
1008 static int
1009 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1010                              u32 macip_acl_index)
1011 {
1012   macip_acl_list_t *a;
1013   int rv;
1014   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1015     {
1016       return -1;
1017     }
1018   a = &am->macip_acls[macip_acl_index];
1019   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1020   /* If there already a MACIP ACL applied, unapply it */
1021   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1022     macip_acl_interface_del_acl(am, sw_if_index);
1023   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1024   /* Apply the classifier tables for L2 ACLs */
1025   rv =
1026     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1027                               a->ip6_table_index, a->l2_table_index, 1);
1028   return rv;
1029 }
1030
1031 static int
1032 macip_acl_del_list (u32 acl_list_index)
1033 {
1034   acl_main_t *am = &acl_main;
1035   macip_acl_list_t *a;
1036   int i;
1037   if (pool_is_free_index (am->macip_acls, acl_list_index))
1038     {
1039       return -1;
1040     }
1041
1042   /* delete any references to the ACL */
1043   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1044     {
1045       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1046         {
1047           macip_acl_interface_del_acl (am, i);
1048         }
1049     }
1050
1051   /* Now that classifier tables are detached, clean them up */
1052   macip_destroy_classify_tables (am, acl_list_index);
1053
1054   /* now we can delete the ACL itself */
1055   a = &am->macip_acls[acl_list_index];
1056   if (a->rules)
1057     {
1058       clib_mem_free (a->rules);
1059     }
1060   pool_put (am->macip_acls, a);
1061   return 0;
1062 }
1063
1064
1065 static int
1066 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1067                                  u32 acl_list_index)
1068 {
1069   acl_main_t *am = &acl_main;
1070   int rv = -1;
1071   if (is_add)
1072     {
1073       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1074     }
1075   else
1076     {
1077       rv = macip_acl_interface_del_acl (am, sw_if_index);
1078     }
1079   return rv;
1080 }
1081
1082 /* API message handler */
1083 static void
1084 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1085 {
1086   vl_api_acl_add_replace_reply_t *rmp;
1087   acl_main_t *am = &acl_main;
1088   int rv;
1089   u32 acl_list_index = ntohl (mp->acl_index);
1090
1091   rv = acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag);
1092
1093   /* *INDENT-OFF* */
1094   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1095   ({
1096     rmp->acl_index = htonl(acl_list_index);
1097   }));
1098   /* *INDENT-ON* */
1099 }
1100
1101 static void
1102 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1103 {
1104   acl_main_t *am = &acl_main;
1105   vl_api_acl_del_reply_t *rmp;
1106   int rv;
1107
1108   rv = acl_del_list (ntohl (mp->acl_index));
1109
1110   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1111 }
1112
1113 static void
1114 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1115 {
1116   acl_main_t *am = &acl_main;
1117   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1118   u32 sw_if_index = ntohl (mp->sw_if_index);
1119   vl_api_acl_interface_add_del_reply_t *rmp;
1120   int rv = -1;
1121
1122   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1123     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1124   else
1125     rv =
1126       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1127                                      mp->is_input, ntohl (mp->acl_index));
1128
1129   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1130 }
1131
1132 static void
1133 vl_api_acl_interface_set_acl_list_t_handler
1134   (vl_api_acl_interface_set_acl_list_t * mp)
1135 {
1136   acl_main_t *am = &acl_main;
1137   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1138   int rv = 0;
1139   int i;
1140   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1141   u32 sw_if_index = ntohl (mp->sw_if_index);
1142
1143   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1144     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1145   else
1146     {
1147       acl_interface_reset_inout_acls (sw_if_index, 0);
1148       acl_interface_reset_inout_acls (sw_if_index, 1);
1149
1150       for (i = 0; i < mp->count; i++)
1151         {
1152           acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1153                                        ntohl (mp->acls[i]));
1154         }
1155     }
1156
1157   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1158 }
1159
1160 static void
1161 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1162 {
1163   api_rule->is_permit = r->is_permit;
1164   api_rule->is_ipv6 = r->is_ipv6;
1165   if(r->is_ipv6)
1166     {
1167       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1168       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1169     }
1170   else
1171     {
1172       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1173       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1174     }
1175   api_rule->src_ip_prefix_len = r->src_prefixlen;
1176   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1177   api_rule->proto = r->proto;
1178   api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
1179   api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
1180   api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
1181   api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
1182   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1183   api_rule->tcp_flags_value = r->tcp_flags_value;
1184 }
1185
1186 static void
1187 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1188                   acl_list_t * acl, u32 context)
1189 {
1190   vl_api_acl_details_t *mp;
1191   vl_api_acl_rule_t *rules;
1192   int i;
1193   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1194
1195   mp = vl_msg_api_alloc (msg_size);
1196   memset (mp, 0, msg_size);
1197   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1198
1199   /* fill in the message */
1200   mp->context = context;
1201   mp->count = htonl (acl->count);
1202   mp->acl_index = htonl (acl - am->acls);
1203   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1204   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1205   rules = mp->r;
1206   for (i = 0; i < acl->count; i++)
1207     {
1208       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1209     }
1210
1211   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1212   vl_msg_api_send_shmem (q, (u8 *) & mp);
1213 }
1214
1215
1216 static void
1217 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1218 {
1219   acl_main_t *am = &acl_main;
1220   u32 acl_index;
1221   acl_list_t *acl;
1222
1223   int rv = -1;
1224   unix_shared_memory_queue_t *q;
1225
1226   q = vl_api_client_index_to_input_queue (mp->client_index);
1227   if (q == 0)
1228     {
1229       return;
1230     }
1231
1232   if (mp->acl_index == ~0)
1233     {
1234     /* *INDENT-OFF* */
1235     /* Just dump all ACLs */
1236     pool_foreach (acl, am->acls,
1237     ({
1238       send_acl_details(am, q, acl, mp->context);
1239     }));
1240     /* *INDENT-ON* */
1241     }
1242   else
1243     {
1244       acl_index = ntohl (mp->acl_index);
1245       if (!pool_is_free_index (am->acls, acl_index))
1246         {
1247           acl = &am->acls[acl_index];
1248           send_acl_details (am, q, acl, mp->context);
1249         }
1250     }
1251
1252   if (rv == -1)
1253     {
1254       /* FIXME API: should we signal an error here at all ? */
1255       return;
1256     }
1257 }
1258
1259 static void
1260 send_acl_interface_list_details (acl_main_t * am,
1261                                  unix_shared_memory_queue_t * q,
1262                                  u32 sw_if_index, u32 context)
1263 {
1264   vl_api_acl_interface_list_details_t *mp;
1265   int msg_size;
1266   int n_input;
1267   int n_output;
1268   int count;
1269   int i = 0;
1270
1271   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1272   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1273
1274   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1275   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1276   count = n_input + n_output;
1277
1278   msg_size = sizeof (*mp);
1279   msg_size += sizeof (mp->acls[0]) * count;
1280
1281   mp = vl_msg_api_alloc (msg_size);
1282   memset (mp, 0, msg_size);
1283   mp->_vl_msg_id =
1284     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1285
1286   /* fill in the message */
1287   mp->context = context;
1288   mp->sw_if_index = htonl (sw_if_index);
1289   mp->count = count;
1290   mp->n_input = n_input;
1291   for (i = 0; i < n_input; i++)
1292     {
1293       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1294     }
1295   for (i = 0; i < n_output; i++)
1296     {
1297       mp->acls[n_input + i] =
1298         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1299     }
1300
1301   vl_msg_api_send_shmem (q, (u8 *) & mp);
1302 }
1303
1304 static void
1305 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1306                                           mp)
1307 {
1308   acl_main_t *am = &acl_main;
1309   vnet_sw_interface_t *swif;
1310   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1311
1312   u32 sw_if_index;
1313   unix_shared_memory_queue_t *q;
1314
1315   q = vl_api_client_index_to_input_queue (mp->client_index);
1316   if (q == 0)
1317     {
1318       return;
1319     }
1320
1321   if (mp->sw_if_index == ~0)
1322     {
1323     /* *INDENT-OFF* */
1324     pool_foreach (swif, im->sw_interfaces,
1325     ({
1326       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1327     }));
1328     /* *INDENT-ON* */
1329     }
1330   else
1331     {
1332       sw_if_index = ntohl (mp->sw_if_index);
1333       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1334         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1335     }
1336 }
1337
1338 /* MACIP ACL API handlers */
1339
1340 static void
1341 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1342 {
1343   vl_api_macip_acl_add_reply_t *rmp;
1344   acl_main_t *am = &acl_main;
1345   int rv;
1346   u32 acl_list_index = ~0;
1347
1348   rv =
1349     macip_acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag);
1350
1351   /* *INDENT-OFF* */
1352   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1353   ({
1354     rmp->acl_index = htonl(acl_list_index);
1355   }));
1356   /* *INDENT-ON* */
1357 }
1358
1359 static void
1360 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1361 {
1362   acl_main_t *am = &acl_main;
1363   vl_api_macip_acl_del_reply_t *rmp;
1364   int rv;
1365
1366   rv = macip_acl_del_list (ntohl (mp->acl_index));
1367
1368   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1369 }
1370
1371 static void
1372 vl_api_macip_acl_interface_add_del_t_handler
1373   (vl_api_macip_acl_interface_add_del_t * mp)
1374 {
1375   acl_main_t *am = &acl_main;
1376   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1377   int rv = -1;
1378   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1379   u32 sw_if_index = ntohl (mp->sw_if_index);
1380
1381   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1382     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1383   else
1384     rv =
1385       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1386                                      ntohl (mp->acl_index));
1387
1388   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1389 }
1390
1391 static void
1392 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1393                         macip_acl_list_t * acl, u32 context)
1394 {
1395   vl_api_macip_acl_details_t *mp;
1396   vl_api_macip_acl_rule_t *rules;
1397   macip_acl_rule_t *r;
1398   int i;
1399   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1400
1401   mp = vl_msg_api_alloc (msg_size);
1402   memset (mp, 0, msg_size);
1403   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1404
1405   /* fill in the message */
1406   mp->context = context;
1407   if (acl)
1408     {
1409       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1410       mp->count = htonl (acl->count);
1411       mp->acl_index = htonl (acl - am->macip_acls);
1412       rules = mp->r;
1413       for (i = 0; i < acl->count; i++)
1414         {
1415           r = &acl->rules[i];
1416           rules[i].is_permit = r->is_permit;
1417           rules[i].is_ipv6 = r->is_ipv6;
1418           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1419           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1420                   sizeof (r->src_mac_mask));
1421           if (r->is_ipv6)
1422             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1423                   sizeof (r->src_ip_addr.ip6));
1424           else
1425             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1426                   sizeof (r->src_ip_addr.ip4));
1427           rules[i].src_ip_prefix_len = r->src_prefixlen;
1428         }
1429     }
1430   else
1431     {
1432       /* No martini, no party - no ACL applied to this interface. */
1433       mp->acl_index = ~0;
1434       mp->count = 0;
1435     }
1436
1437   vl_msg_api_send_shmem (q, (u8 *) & mp);
1438 }
1439
1440
1441 static void
1442 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1443 {
1444   acl_main_t *am = &acl_main;
1445   macip_acl_list_t *acl;
1446
1447   unix_shared_memory_queue_t *q;
1448
1449   q = vl_api_client_index_to_input_queue (mp->client_index);
1450   if (q == 0)
1451     {
1452       return;
1453     }
1454
1455   if (mp->acl_index == ~0)
1456     {
1457       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1458       pool_foreach (acl, am->macip_acls, (
1459                                            {
1460                                            send_macip_acl_details (am, q, acl,
1461                                                                    mp->
1462                                                                    context);}
1463                     ));
1464       /* *INDENT-ON* */
1465     }
1466   else
1467     {
1468       u32 acl_index = ntohl (mp->acl_index);
1469       if (!pool_is_free_index (am->macip_acls, acl_index))
1470         {
1471           acl = &am->macip_acls[acl_index];
1472           send_macip_acl_details (am, q, acl, mp->context);
1473         }
1474     }
1475 }
1476
1477 static void
1478 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1479                                           mp)
1480 {
1481   acl_main_t *am = &acl_main;
1482   vl_api_macip_acl_interface_get_reply_t *rmp;
1483   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1484   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1485   unix_shared_memory_queue_t *q;
1486   int i;
1487
1488   q = vl_api_client_index_to_input_queue (mp->client_index);
1489   if (q == 0)
1490     {
1491       return;
1492     }
1493
1494   rmp = vl_msg_api_alloc (msg_size);
1495   memset (rmp, 0, msg_size);
1496   rmp->_vl_msg_id =
1497     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1498   rmp->context = mp->context;
1499   rmp->count = htonl (count);
1500   for (i = 0; i < count; i++)
1501     {
1502       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1503     }
1504
1505   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1506 }
1507
1508 /* Set up the API message handling tables */
1509 static clib_error_t *
1510 acl_plugin_api_hookup (vlib_main_t * vm)
1511 {
1512   acl_main_t *am = &acl_main;
1513 #define _(N,n)                                                  \
1514     vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base),     \
1515                            #n,                                  \
1516                            vl_api_##n##_t_handler,              \
1517                            vl_noop_handler,                     \
1518                            vl_api_##n##_t_endian,               \
1519                            vl_api_##n##_t_print,                \
1520                            sizeof(vl_api_##n##_t), 1);
1521   foreach_acl_plugin_api_msg;
1522 #undef _
1523
1524   return 0;
1525 }
1526
1527 #define vl_msg_name_crc_list
1528 #include <acl/acl_all_api_h.h>
1529 #undef vl_msg_name_crc_list
1530
1531 static void
1532 setup_message_id_table (acl_main_t * am, api_main_t * apim)
1533 {
1534 #define _(id,n,crc) \
1535   vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
1536   foreach_vl_msg_name_crc_acl;
1537 #undef _
1538 }
1539
1540 static void
1541 acl_setup_fa_nodes (void)
1542 {
1543   vlib_main_t *vm = vlib_get_main ();
1544   acl_main_t *am = &acl_main;
1545   vlib_node_t *n, *n4, *n6;
1546
1547   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1548   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
1549   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
1550
1551
1552   am->l2_input_classify_next_acl_ip4 =
1553     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1554   am->l2_input_classify_next_acl_ip6 =
1555     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1556
1557   feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
1558                                l2input_get_feat_names (),
1559                                am->fa_acl_in_ip4_l2_node_feat_next_node_index);
1560
1561   feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
1562                                l2input_get_feat_names (),
1563                                am->fa_acl_in_ip6_l2_node_feat_next_node_index);
1564
1565
1566   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1567   n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
1568   n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
1569
1570   am->l2_output_classify_next_acl_ip4 =
1571     vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
1572   am->l2_output_classify_next_acl_ip6 =
1573     vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
1574
1575   feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
1576                                l2output_get_feat_names (),
1577                                am->fa_acl_out_ip4_l2_node_feat_next_node_index);
1578
1579   feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
1580                                l2output_get_feat_names (),
1581                                am->fa_acl_out_ip6_l2_node_feat_next_node_index);
1582 }
1583
1584 static void
1585 acl_set_timeout_sec(int timeout_type, u32 value)
1586 {
1587   acl_main_t *am = &acl_main;
1588   clib_time_t *ct = &am->vlib_main->clib_time;
1589
1590   if (timeout_type < ACL_N_TIMEOUTS) {
1591     am->session_timeout_sec[timeout_type] = value;
1592   } else {
1593     clib_warning("Unknown timeout type %d", timeout_type);
1594     return;
1595   }
1596   am->session_timeout[timeout_type] = (u64)(((f64)value)/ct->seconds_per_clock);
1597 }
1598
1599 static void
1600 acl_set_session_max_entries(u32 value)
1601 {
1602   acl_main_t *am = &acl_main;
1603   am->fa_conn_table_max_entries = value;
1604 }
1605
1606 static int
1607 acl_set_skip_ipv6_eh(u32 eh, u32 value)
1608 {
1609   acl_main_t *am = &acl_main;
1610   if ((eh < 256) && (value < 2))
1611     {
1612       am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, eh, value);
1613       return 1;
1614     }
1615   else
1616     return 0;
1617 }
1618
1619
1620 static clib_error_t *
1621 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
1622 {
1623   acl_main_t *am = &acl_main;
1624   if (0 == is_add) {
1625     vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
1626                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, sw_if_index);
1627   }
1628   return 0;
1629 }
1630
1631 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
1632
1633 static clib_error_t *
1634 acl_set_aclplugin_fn (vlib_main_t * vm,
1635                               unformat_input_t * input,
1636                               vlib_cli_command_t * cmd)
1637 {
1638   clib_error_t *error = 0;
1639   u32 timeout = 0;
1640   u32 val = 0;
1641   u32 eh_val = 0;
1642   uword memory_size = 0;
1643   acl_main_t *am = &acl_main;
1644
1645   if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val)) {
1646     if(!acl_set_skip_ipv6_eh(eh_val, val)) {
1647       error = clib_error_return(0, "expecting eh=0..255, value=0..1");
1648     }
1649     goto done;
1650   }
1651   if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
1652     {
1653       am->l4_match_nonfirst_fragment = (val != 0);
1654       goto done;
1655     }
1656   if (unformat (input, "session")) {
1657     if (unformat (input, "clear")) {
1658       acl_main_t *am = &acl_main;
1659       vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
1660                                ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
1661           goto done;
1662     }
1663     if (unformat (input, "table")) {
1664       /* The commands here are for tuning/testing. No user-serviceable parts inside */
1665       if (unformat (input, "max-entries")) {
1666         if (!unformat(input, "%u", &val)) {
1667           error = clib_error_return(0,
1668                                     "expecting maximum number of entries, got `%U`",
1669                                     format_unformat_error, input);
1670           goto done;
1671         } else {
1672           acl_set_session_max_entries(val);
1673           goto done;
1674         }
1675       }
1676       if (unformat (input, "hash-table-buckets")) {
1677         if (!unformat(input, "%u", &val)) {
1678           error = clib_error_return(0,
1679                                     "expecting maximum number of hash table buckets, got `%U`",
1680                                     format_unformat_error, input);
1681           goto done;
1682         } else {
1683           am->fa_conn_table_hash_num_buckets = val;
1684           goto done;
1685         }
1686       }
1687       if (unformat (input, "hash-table-memory")) {
1688         if (!unformat(input, "%U", unformat_memory_size, &memory_size)) {
1689           error = clib_error_return(0,
1690                                     "expecting maximum amount of hash table memory, got `%U`",
1691                                     format_unformat_error, input);
1692           goto done;
1693         } else {
1694           am->fa_conn_table_hash_memory_size = memory_size;
1695           goto done;
1696         }
1697       }
1698       goto done;
1699     }
1700     if (unformat (input, "timeout")) {
1701       if (unformat(input, "udp")) {
1702         if(unformat(input, "idle")) {
1703           if (!unformat(input, "%u", &timeout)) {
1704             error = clib_error_return(0,
1705                                       "expecting timeout value in seconds, got `%U`",
1706                                       format_unformat_error, input);
1707             goto done;
1708           } else {
1709             acl_set_timeout_sec(ACL_TIMEOUT_UDP_IDLE, timeout);
1710             goto done;
1711           }
1712         }
1713       }
1714       if (unformat(input, "tcp")) {
1715         if(unformat(input, "idle")) {
1716           if (!unformat(input, "%u", &timeout)) {
1717             error = clib_error_return(0,
1718                                       "expecting timeout value in seconds, got `%U`",
1719                                       format_unformat_error, input);
1720             goto done;
1721           } else {
1722             acl_set_timeout_sec(ACL_TIMEOUT_TCP_IDLE, timeout);
1723             goto done;
1724           }
1725         }
1726         if(unformat(input, "transient")) {
1727           if (!unformat(input, "%u", &timeout)) {
1728             error = clib_error_return(0,
1729                                       "expecting timeout value in seconds, got `%U`",
1730                                       format_unformat_error, input);
1731             goto done;
1732           } else {
1733             acl_set_timeout_sec(ACL_TIMEOUT_TCP_TRANSIENT, timeout);
1734             goto done;
1735           }
1736         }
1737       }
1738       goto done;
1739     }
1740   }
1741 done:
1742   return error;
1743 }
1744
1745 static clib_error_t *
1746 acl_show_aclplugin_fn (vlib_main_t * vm,
1747                               unformat_input_t * input,
1748                               vlib_cli_command_t * cmd)
1749 {
1750   clib_error_t *error = 0;
1751   acl_main_t *am = &acl_main;
1752   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1753
1754   vnet_sw_interface_t *swif;
1755
1756   if (unformat (input, "sessions"))
1757     {
1758       u8 * out0 = 0;
1759       pool_foreach (swif, im->sw_interfaces,
1760       ({
1761         u32 sw_if_index =  swif->sw_if_index;
1762         u64 n_adds = sw_if_index < vec_len(am->fa_session_adds_by_sw_if_index) ? am->fa_session_adds_by_sw_if_index[sw_if_index] : 0;
1763         u64 n_dels = sw_if_index < vec_len(am->fa_session_dels_by_sw_if_index) ? am->fa_session_dels_by_sw_if_index[sw_if_index] : 0;
1764         out0 = format(out0, "sw_if_index %d: add %lu - del %lu = %lu\n", sw_if_index, n_adds, n_dels, n_adds - n_dels);
1765       }));
1766       out0 = format(out0, "\n\nConn cleaner thread counters:\n");
1767 #define _(cnt, desc) out0 = format(out0, "             %20lu: %s\n", am->cnt, desc);
1768       foreach_fa_cleaner_counter;
1769 #undef _
1770       vlib_cli_output(vm, "\n\n%s\n\n", out0);
1771       vlib_cli_output(vm, "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
1772               am->fa_min_deleted_sessions_per_interval, am->fa_max_deleted_sessions_per_interval,
1773               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);
1774
1775       vec_free(out0);
1776     }
1777   return error;
1778 }
1779
1780
1781  /* *INDENT-OFF* */
1782 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
1783     .path = "set acl-plugin",
1784     .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
1785     .function = acl_set_aclplugin_fn,
1786 };
1787
1788 VLIB_CLI_COMMAND (aclplugin_show_command, static) = {
1789     .path = "show acl-plugin",
1790     .short_help = "show acl-plugin sessions",
1791     .function = acl_show_aclplugin_fn,
1792 };
1793 /* *INDENT-ON* */
1794
1795
1796
1797 static clib_error_t *
1798 acl_init (vlib_main_t * vm)
1799 {
1800   acl_main_t *am = &acl_main;
1801   clib_error_t *error = 0;
1802   memset (am, 0, sizeof (*am));
1803   am->vlib_main = vm;
1804   am->vnet_main = vnet_get_main ();
1805
1806   u8 *name = format (0, "acl_%08x%c", api_version, 0);
1807
1808   /* Ask for a correctly-sized block of API message decode slots */
1809   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
1810                                             VL_MSG_FIRST_AVAILABLE);
1811
1812   error = acl_plugin_api_hookup (vm);
1813
1814  /* Add our API messages to the global name_crc hash table */
1815   setup_message_id_table (am, &api_main);
1816
1817   vec_free (name);
1818
1819   acl_setup_fa_nodes();
1820   am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] = TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
1821   am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] = TCP_SESSION_IDLE_TIMEOUT_SEC;
1822   am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] = UDP_SESSION_IDLE_TIMEOUT_SEC;
1823
1824   am->fa_conn_table_hash_num_buckets = ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
1825   am->fa_conn_table_hash_memory_size = ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
1826   am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
1827
1828   {
1829     u8 tt;
1830     for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) {
1831        am->fa_conn_list_head[tt] = ~0;
1832        am->fa_conn_list_tail[tt] = ~0;
1833     }
1834   }
1835
1836   am->fa_min_deleted_sessions_per_interval = ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
1837   am->fa_max_deleted_sessions_per_interval = ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
1838   am->fa_cleaner_wait_time_increment = ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
1839
1840   am->fa_cleaner_cnt_delete_by_sw_index = 0;
1841   am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
1842   am->fa_cleaner_cnt_unknown_event = 0;
1843   am->fa_cleaner_cnt_deleted_sessions = 0;
1844   am->fa_cleaner_cnt_timer_restarted = 0;
1845   am->fa_cleaner_cnt_wait_with_timeout = 0;
1846
1847
1848 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
1849   foreach_acl_eh
1850 #undef _
1851
1852   am->l4_match_nonfirst_fragment = 1;
1853
1854   return error;
1855 }
1856
1857 VLIB_INIT_FUNCTION (acl_init);