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