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