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