Move java,lua api and remaining plugins to src/
[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 } macip_match_type_t;
1048
1049 static u32
1050 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
1051                        u8 is_ipv6)
1052 {
1053   u32 i;
1054   if (mv)
1055     {
1056       for (i = 0; i < vec_len (mv); i++)
1057         {
1058           if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
1059               && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
1060             {
1061               return i;
1062             }
1063         }
1064     }
1065   return ~0;
1066 }
1067
1068
1069 /* Get metric used to sort match types.
1070    The more specific and the more often seen - the bigger the metric */
1071 static int
1072 match_type_metric (macip_match_type_t * m)
1073 {
1074   /* FIXME: count the ones in the MAC mask as well, check how well this heuristic works in real life */
1075   return m->prefix_len + m->is_ipv6 + 10 * m->count;
1076 }
1077
1078 static int
1079 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
1080 {
1081   /* Ascending sort based on the metric values */
1082   return match_type_metric (m1) - match_type_metric (m2);
1083 }
1084
1085 /* Get the offset of L3 source within ethernet packet */
1086 static int
1087 get_l3_src_offset(int is6)
1088 {
1089   if(is6)
1090     return (sizeof(ethernet_header_t) + offsetof(ip6_header_t, src_address));
1091   else
1092     return (sizeof(ethernet_header_t) + offsetof(ip4_header_t, src_address));
1093 }
1094
1095 static int
1096 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
1097 {
1098   macip_match_type_t *mvec = NULL;
1099   macip_match_type_t *mt;
1100   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
1101   int i;
1102   u32 match_type_index;
1103   u32 last_table;
1104   u8 mask[5 * 16];
1105   vnet_classify_main_t *cm = &vnet_classify_main;
1106
1107   /* Count the number of different types of rules */
1108   for (i = 0; i < a->count; i++)
1109     {
1110       if (~0 ==
1111           (match_type_index =
1112            macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1113                                   a->rules[i].src_prefixlen,
1114                                   a->rules[i].is_ipv6)))
1115         {
1116           match_type_index = vec_len (mvec);
1117           vec_validate (mvec, match_type_index);
1118           memcpy (mvec[match_type_index].mac_mask,
1119                   a->rules[match_type_index].src_mac_mask, 6);
1120           mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1121           mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1122           mvec[match_type_index].table_index = ~0;
1123         }
1124       mvec[match_type_index].count++;
1125     }
1126   /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1127   vec_sort_with_function (mvec, match_type_compare);
1128   /* Create the classifier tables */
1129   last_table = ~0;
1130   vec_foreach (mt, mvec)
1131   {
1132     int mask_len;
1133     int is6 = mt->is_ipv6;
1134     int l3_src_offs = get_l3_src_offset(is6);
1135     memset (mask, 0, sizeof (mask));
1136     memcpy (&mask[6], mt->mac_mask, 6);
1137     for (i = 0; i < (mt->prefix_len / 8); i++)
1138       {
1139         mask[l3_src_offs + i] = 0xff;
1140       }
1141     if (mt->prefix_len % 8)
1142       {
1143         mask[l3_src_offs + (mt->prefix_len / 8)] =
1144           0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1145       }
1146     /*
1147      * Round-up the number of bytes needed to store the prefix,
1148      * and round up the number of vectors too
1149      */
1150     mask_len = ((l3_src_offs + ((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->table_index,
1154                                 1);
1155     last_table = mt->table_index;
1156   }
1157   a->ip4_table_index = ~0;
1158   a->ip6_table_index = ~0;
1159   a->l2_table_index = last_table;
1160
1161   /* Populate the classifier tables with rules from the MACIP ACL */
1162   for (i = 0; i < a->count; i++)
1163     {
1164       u32 action = 0;
1165       u32 metadata = 0;
1166       int is6 = a->rules[i].is_ipv6;
1167       int l3_src_offs = get_l3_src_offset(is6);
1168       memset (mask, 0, sizeof (mask));
1169       memcpy (&mask[6], a->rules[i].src_mac, 6);
1170       if (is6)
1171         {
1172           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1173         }
1174       else
1175         {
1176           memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1177         }
1178       match_type_index =
1179         macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1180                                a->rules[i].src_prefixlen,
1181                                a->rules[i].is_ipv6);
1182       /* add session to table mvec[match_type_index].table_index; */
1183       vnet_classify_add_del_session (cm, mvec[match_type_index].table_index,
1184                                      mask, a->rules[i].is_permit ? ~0 : 0, i,
1185                                      0, action, metadata, 1);
1186     }
1187   return 0;
1188 }
1189
1190 static void
1191 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1192 {
1193   vnet_classify_main_t *cm = &vnet_classify_main;
1194   macip_acl_list_t *a = &am->macip_acls[macip_acl_index];
1195
1196   if (a->ip4_table_index != ~0)
1197     {
1198       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip4_table_index, 0);
1199       a->ip4_table_index = ~0;
1200     }
1201   if (a->ip6_table_index != ~0)
1202     {
1203       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->ip6_table_index, 0);
1204       a->ip6_table_index = ~0;
1205     }
1206   if (a->l2_table_index != ~0)
1207     {
1208       acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index, 0);
1209       a->l2_table_index = ~0;
1210     }
1211 }
1212
1213 static int
1214 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1215                     u32 * acl_list_index, u8 * tag)
1216 {
1217   acl_main_t *am = &acl_main;
1218   macip_acl_list_t *a;
1219   macip_acl_rule_t *r;
1220   macip_acl_rule_t *acl_new_rules;
1221   int i;
1222
1223   /* Create and populate the rules */
1224   acl_new_rules = clib_mem_alloc_aligned (sizeof (macip_acl_rule_t) * count,
1225                                           CLIB_CACHE_LINE_BYTES);
1226   if (!acl_new_rules)
1227     {
1228       /* Could not allocate rules. New or existing ACL - bail out regardless */
1229       return -1;
1230     }
1231
1232   for (i = 0; i < count; i++)
1233     {
1234       r = &acl_new_rules[i];
1235       r->is_permit = rules[i].is_permit;
1236       r->is_ipv6 = rules[i].is_ipv6;
1237       memcpy (&r->src_mac, rules[i].src_mac, 6);
1238       memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1239       if(rules[i].is_ipv6)
1240         memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1241       else
1242         memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1243       r->src_prefixlen = rules[i].src_ip_prefix_len;
1244     }
1245
1246   /* Get ACL index */
1247   pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1248   memset (a, 0, sizeof (*a));
1249   /* Will return the newly allocated ACL index */
1250   *acl_list_index = a - am->macip_acls;
1251
1252   a->rules = acl_new_rules;
1253   a->count = count;
1254   memcpy (a->tag, tag, sizeof (a->tag));
1255
1256   /* Create and populate the classifer tables */
1257   macip_create_classify_tables (am, *acl_list_index);
1258
1259   return 0;
1260 }
1261
1262
1263 /* No check for validity of sw_if_index - the callers were supposed to validate */
1264
1265 static int
1266 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1267 {
1268   int rv;
1269   u32 macip_acl_index;
1270   macip_acl_list_t *a;
1271   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1272   macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1273   /* No point in deleting MACIP ACL which is not applied */
1274   if (~0 == macip_acl_index)
1275     return -1;
1276   a = &am->macip_acls[macip_acl_index];
1277   /* remove the classifier tables off the interface L2 ACL */
1278   rv =
1279     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1280                               a->ip6_table_index, a->l2_table_index, 0);
1281   /* Unset the MACIP ACL index */
1282   am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
1283   return rv;
1284 }
1285
1286 /* No check for validity of sw_if_index - the callers were supposed to validate */
1287
1288 static int
1289 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
1290                              u32 macip_acl_index)
1291 {
1292   macip_acl_list_t *a;
1293   int rv;
1294   if (pool_is_free_index (am->macip_acls, macip_acl_index))
1295     {
1296       return -1;
1297     }
1298   a = &am->macip_acls[macip_acl_index];
1299   vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1300   /* If there already a MACIP ACL applied, unapply it */
1301   if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
1302     macip_acl_interface_del_acl(am, sw_if_index);
1303   am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
1304   /* Apply the classifier tables for L2 ACLs */
1305   rv =
1306     vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
1307                               a->ip6_table_index, a->l2_table_index, 1);
1308   return rv;
1309 }
1310
1311 static int
1312 macip_acl_del_list (u32 acl_list_index)
1313 {
1314   acl_main_t *am = &acl_main;
1315   macip_acl_list_t *a;
1316   int i;
1317   if (pool_is_free_index (am->macip_acls, acl_list_index))
1318     {
1319       return -1;
1320     }
1321
1322   /* delete any references to the ACL */
1323   for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1324     {
1325       if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
1326         {
1327           macip_acl_interface_del_acl (am, i);
1328         }
1329     }
1330
1331   /* Now that classifier tables are detached, clean them up */
1332   macip_destroy_classify_tables (am, acl_list_index);
1333
1334   /* now we can delete the ACL itself */
1335   a = &am->macip_acls[acl_list_index];
1336   if (a->rules)
1337     {
1338       clib_mem_free (a->rules);
1339     }
1340   pool_put (am->macip_acls, a);
1341   return 0;
1342 }
1343
1344
1345 static int
1346 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
1347                                  u32 acl_list_index)
1348 {
1349   acl_main_t *am = &acl_main;
1350   int rv = -1;
1351   if (is_add)
1352     {
1353       rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
1354     }
1355   else
1356     {
1357       rv = macip_acl_interface_del_acl (am, sw_if_index);
1358     }
1359   return rv;
1360 }
1361
1362 /* API message handler */
1363 static void
1364 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
1365 {
1366   vl_api_acl_add_replace_reply_t *rmp;
1367   acl_main_t *am = &acl_main;
1368   int rv;
1369   u32 acl_list_index = ntohl (mp->acl_index);
1370
1371   rv = acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag);
1372
1373   /* *INDENT-OFF* */
1374   REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
1375   ({
1376     rmp->acl_index = htonl(acl_list_index);
1377   }));
1378   /* *INDENT-ON* */
1379 }
1380
1381 static void
1382 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
1383 {
1384   acl_main_t *sm = &acl_main;
1385   vl_api_acl_del_reply_t *rmp;
1386   int rv;
1387
1388   rv = acl_del_list (ntohl (mp->acl_index));
1389
1390   REPLY_MACRO (VL_API_ACL_DEL_REPLY);
1391 }
1392
1393 static void
1394 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
1395 {
1396   acl_main_t *sm = &acl_main;
1397   vnet_interface_main_t *im = &sm->vnet_main->interface_main;
1398   u32 sw_if_index = ntohl (mp->sw_if_index);
1399   vl_api_acl_interface_add_del_reply_t *rmp;
1400   int rv = -1;
1401
1402   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1403     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1404   else
1405     rv =
1406       acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
1407                                      mp->is_input, ntohl (mp->acl_index));
1408
1409   REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
1410 }
1411
1412 static void
1413 vl_api_acl_interface_set_acl_list_t_handler
1414   (vl_api_acl_interface_set_acl_list_t * mp)
1415 {
1416   acl_main_t *sm = &acl_main;
1417   vl_api_acl_interface_set_acl_list_reply_t *rmp;
1418   int rv = 0;
1419   int i;
1420   vnet_interface_main_t *im = &sm->vnet_main->interface_main;
1421   u32 sw_if_index = ntohl (mp->sw_if_index);
1422
1423   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1424     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1425   else
1426     {
1427       acl_interface_reset_inout_acls (sw_if_index, 0);
1428       acl_interface_reset_inout_acls (sw_if_index, 1);
1429
1430       for (i = 0; i < mp->count; i++)
1431         {
1432           acl_interface_add_del_inout_acl (sw_if_index, 1, (i < mp->n_input),
1433                                        ntohl (mp->acls[i]));
1434         }
1435     }
1436
1437   REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
1438 }
1439
1440 static void
1441 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
1442 {
1443   api_rule->is_permit = r->is_permit;
1444   api_rule->is_ipv6 = r->is_ipv6;
1445   if(r->is_ipv6)
1446     {
1447       memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
1448       memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
1449     }
1450   else
1451     {
1452       memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
1453       memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
1454     }
1455   api_rule->src_ip_prefix_len = r->src_prefixlen;
1456   api_rule->dst_ip_prefix_len = r->dst_prefixlen;
1457   api_rule->proto = r->proto;
1458   api_rule->srcport_or_icmptype_first = r->src_port_or_type_first;
1459   api_rule->srcport_or_icmptype_last = r->src_port_or_type_last;
1460   api_rule->dstport_or_icmpcode_first = r->dst_port_or_code_first;
1461   api_rule->dstport_or_icmpcode_last = r->dst_port_or_code_last;
1462   api_rule->tcp_flags_mask = r->tcp_flags_mask;
1463   api_rule->tcp_flags_value = r->tcp_flags_value;
1464 }
1465
1466 static void
1467 send_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1468                   acl_list_t * acl, u32 context)
1469 {
1470   vl_api_acl_details_t *mp;
1471   vl_api_acl_rule_t *rules;
1472   int i;
1473   int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
1474
1475   mp = vl_msg_api_alloc (msg_size);
1476   memset (mp, 0, msg_size);
1477   mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
1478
1479   /* fill in the message */
1480   mp->context = context;
1481   mp->count = htonl (acl->count);
1482   mp->acl_index = htonl (acl - am->acls);
1483   memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1484   // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
1485   rules = mp->r;
1486   for (i = 0; i < acl->count; i++)
1487     {
1488       copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
1489     }
1490
1491   clib_warning("Sending acl details for ACL index %d", ntohl(mp->acl_index));
1492   vl_msg_api_send_shmem (q, (u8 *) & mp);
1493 }
1494
1495
1496 static void
1497 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
1498 {
1499   acl_main_t *am = &acl_main;
1500   u32 acl_index;
1501   acl_list_t *acl;
1502
1503   int rv = -1;
1504   unix_shared_memory_queue_t *q;
1505
1506   q = vl_api_client_index_to_input_queue (mp->client_index);
1507   if (q == 0)
1508     {
1509       return;
1510     }
1511
1512   if (mp->acl_index == ~0)
1513     {
1514     /* *INDENT-OFF* */
1515     /* Just dump all ACLs */
1516     pool_foreach (acl, am->acls,
1517     ({
1518       send_acl_details(am, q, acl, mp->context);
1519     }));
1520     /* *INDENT-ON* */
1521     }
1522   else
1523     {
1524       acl_index = ntohl (mp->acl_index);
1525       if (!pool_is_free_index (am->acls, acl_index))
1526         {
1527           acl = &am->acls[acl_index];
1528           send_acl_details (am, q, acl, mp->context);
1529         }
1530     }
1531
1532   if (rv == -1)
1533     {
1534       /* FIXME API: should we signal an error here at all ? */
1535       return;
1536     }
1537 }
1538
1539 static void
1540 send_acl_interface_list_details (acl_main_t * am,
1541                                  unix_shared_memory_queue_t * q,
1542                                  u32 sw_if_index, u32 context)
1543 {
1544   vl_api_acl_interface_list_details_t *mp;
1545   int msg_size;
1546   int n_input;
1547   int n_output;
1548   int count;
1549   int i = 0;
1550
1551   vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1552   vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1553
1554   n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1555   n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1556   count = n_input + n_output;
1557
1558   msg_size = sizeof (*mp);
1559   msg_size += sizeof (mp->acls[0]) * count;
1560
1561   mp = vl_msg_api_alloc (msg_size);
1562   memset (mp, 0, msg_size);
1563   mp->_vl_msg_id =
1564     ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
1565
1566   /* fill in the message */
1567   mp->context = context;
1568   mp->sw_if_index = htonl (sw_if_index);
1569   mp->count = count;
1570   mp->n_input = n_input;
1571   for (i = 0; i < n_input; i++)
1572     {
1573       mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
1574     }
1575   for (i = 0; i < n_output; i++)
1576     {
1577       mp->acls[n_input + i] =
1578         htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
1579     }
1580
1581   vl_msg_api_send_shmem (q, (u8 *) & mp);
1582 }
1583
1584 static void
1585 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
1586                                           mp)
1587 {
1588   acl_main_t *am = &acl_main;
1589   vnet_sw_interface_t *swif;
1590   vnet_interface_main_t *im = &am->vnet_main->interface_main;
1591
1592   u32 sw_if_index;
1593   unix_shared_memory_queue_t *q;
1594
1595   q = vl_api_client_index_to_input_queue (mp->client_index);
1596   if (q == 0)
1597     {
1598       return;
1599     }
1600
1601   if (mp->sw_if_index == ~0)
1602     {
1603     /* *INDENT-OFF* */
1604     pool_foreach (swif, im->sw_interfaces,
1605     ({
1606       send_acl_interface_list_details(am, q, swif->sw_if_index, mp->context);
1607     }));
1608     /* *INDENT-ON* */
1609     }
1610   else
1611     {
1612       sw_if_index = ntohl (mp->sw_if_index);
1613       if (!pool_is_free_index(im->sw_interfaces, sw_if_index))
1614         send_acl_interface_list_details (am, q, sw_if_index, mp->context);
1615     }
1616 }
1617
1618 /* MACIP ACL API handlers */
1619
1620 static void
1621 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
1622 {
1623   vl_api_macip_acl_add_reply_t *rmp;
1624   acl_main_t *am = &acl_main;
1625   int rv;
1626   u32 acl_list_index = ~0;
1627
1628   rv =
1629     macip_acl_add_list (ntohl (mp->count), mp->r, &acl_list_index, mp->tag);
1630
1631   /* *INDENT-OFF* */
1632   REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
1633   ({
1634     rmp->acl_index = htonl(acl_list_index);
1635   }));
1636   /* *INDENT-ON* */
1637 }
1638
1639 static void
1640 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
1641 {
1642   acl_main_t *sm = &acl_main;
1643   vl_api_macip_acl_del_reply_t *rmp;
1644   int rv;
1645
1646   rv = macip_acl_del_list (ntohl (mp->acl_index));
1647
1648   REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
1649 }
1650
1651 static void
1652 vl_api_macip_acl_interface_add_del_t_handler
1653   (vl_api_macip_acl_interface_add_del_t * mp)
1654 {
1655   acl_main_t *sm = &acl_main;
1656   vl_api_macip_acl_interface_add_del_reply_t *rmp;
1657   int rv = -1;
1658   vnet_interface_main_t *im = &sm->vnet_main->interface_main;
1659   u32 sw_if_index = ntohl (mp->sw_if_index);
1660
1661   if (pool_is_free_index(im->sw_interfaces, sw_if_index))
1662     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
1663   else
1664     rv =
1665       macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
1666                                      ntohl (mp->acl_index));
1667
1668   REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
1669 }
1670
1671 static void
1672 send_macip_acl_details (acl_main_t * am, unix_shared_memory_queue_t * q,
1673                         macip_acl_list_t * acl, u32 context)
1674 {
1675   vl_api_macip_acl_details_t *mp;
1676   vl_api_macip_acl_rule_t *rules;
1677   macip_acl_rule_t *r;
1678   int i;
1679   int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
1680
1681   mp = vl_msg_api_alloc (msg_size);
1682   memset (mp, 0, msg_size);
1683   mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
1684
1685   /* fill in the message */
1686   mp->context = context;
1687   if (acl)
1688     {
1689       memcpy (mp->tag, acl->tag, sizeof (mp->tag));
1690       mp->count = htonl (acl->count);
1691       mp->acl_index = htonl (acl - am->macip_acls);
1692       rules = mp->r;
1693       for (i = 0; i < acl->count; i++)
1694         {
1695           r = &acl->rules[i];
1696           rules[i].is_permit = r->is_permit;
1697           rules[i].is_ipv6 = r->is_ipv6;
1698           memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
1699           memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
1700                   sizeof (r->src_mac_mask));
1701           if (r->is_ipv6)
1702             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
1703                   sizeof (r->src_ip_addr.ip6));
1704           else
1705             memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
1706                   sizeof (r->src_ip_addr.ip4));
1707           rules[i].src_ip_prefix_len = r->src_prefixlen;
1708         }
1709     }
1710   else
1711     {
1712       /* No martini, no party - no ACL applied to this interface. */
1713       mp->acl_index = ~0;
1714       mp->count = 0;
1715     }
1716
1717   vl_msg_api_send_shmem (q, (u8 *) & mp);
1718 }
1719
1720
1721 static void
1722 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
1723 {
1724   acl_main_t *am = &acl_main;
1725   macip_acl_list_t *acl;
1726
1727   unix_shared_memory_queue_t *q;
1728
1729   q = vl_api_client_index_to_input_queue (mp->client_index);
1730   if (q == 0)
1731     {
1732       return;
1733     }
1734
1735   if (mp->acl_index == ~0)
1736     {
1737       /* Just dump all ACLs for now, with sw_if_index = ~0 */
1738       pool_foreach (acl, am->macip_acls, (
1739                                            {
1740                                            send_macip_acl_details (am, q, acl,
1741                                                                    mp->
1742                                                                    context);}
1743                     ));
1744       /* *INDENT-ON* */
1745     }
1746   else
1747     {
1748       u32 acl_index = ntohl (mp->acl_index);
1749       if (!pool_is_free_index (am->macip_acls, acl_index))
1750         {
1751           acl = &am->macip_acls[acl_index];
1752           send_macip_acl_details (am, q, acl, mp->context);
1753         }
1754     }
1755 }
1756
1757 static void
1758 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
1759                                           mp)
1760 {
1761   acl_main_t *am = &acl_main;
1762   vl_api_macip_acl_interface_get_reply_t *rmp;
1763   u32 count = vec_len (am->macip_acl_by_sw_if_index);
1764   int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
1765   unix_shared_memory_queue_t *q;
1766   int i;
1767
1768   q = vl_api_client_index_to_input_queue (mp->client_index);
1769   if (q == 0)
1770     {
1771       return;
1772     }
1773
1774   rmp = vl_msg_api_alloc (msg_size);
1775   memset (rmp, 0, msg_size);
1776   rmp->_vl_msg_id =
1777     ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
1778   rmp->context = mp->context;
1779   rmp->count = htonl (count);
1780   for (i = 0; i < count; i++)
1781     {
1782       rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
1783     }
1784
1785   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1786 }
1787
1788
1789
1790 /* Set up the API message handling tables */
1791 static clib_error_t *
1792 acl_plugin_api_hookup (vlib_main_t * vm)
1793 {
1794   acl_main_t *sm = &acl_main;
1795 #define _(N,n)                                                  \
1796     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
1797                            #n,                                  \
1798                            vl_api_##n##_t_handler,              \
1799                            vl_noop_handler,                     \
1800                            vl_api_##n##_t_endian,               \
1801                            vl_api_##n##_t_print,                \
1802                            sizeof(vl_api_##n##_t), 1);
1803   foreach_acl_plugin_api_msg;
1804 #undef _
1805
1806   return 0;
1807 }
1808
1809 #define vl_msg_name_crc_list
1810 #include <acl/acl_all_api_h.h>
1811 #undef vl_msg_name_crc_list
1812
1813 static void
1814 setup_message_id_table (acl_main_t * sm, api_main_t * am)
1815 {
1816 #define _(id,n,crc) \
1817   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1818   foreach_vl_msg_name_crc_acl;
1819 #undef _
1820 }
1821
1822 u32
1823 register_match_action_nexts (u32 next_in_ip4, u32 next_in_ip6,
1824                              u32 next_out_ip4, u32 next_out_ip6)
1825 {
1826   acl_main_t *am = &acl_main;
1827   u32 act = am->n_match_actions;
1828   if (am->n_match_actions == 255)
1829     {
1830       return ~0;
1831     }
1832   am->n_match_actions++;
1833   am->acl_in_ip4_match_next[act] = next_in_ip4;
1834   am->acl_in_ip6_match_next[act] = next_in_ip6;
1835   am->acl_out_ip4_match_next[act] = next_out_ip4;
1836   am->acl_out_ip6_match_next[act] = next_out_ip6;
1837   return act;
1838 }
1839
1840 void
1841 acl_setup_nodes (void)
1842 {
1843   vlib_main_t *vm = vlib_get_main ();
1844   acl_main_t *am = &acl_main;
1845   vlib_node_t *n;
1846
1847   n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
1848   am->l2_input_classify_next_acl =
1849     vlib_node_add_next_with_slot (vm, n->index, acl_in_node.index, ~0);
1850   n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
1851   am->l2_output_classify_next_acl =
1852     vlib_node_add_next_with_slot (vm, n->index, acl_out_node.index, ~0);
1853
1854   feat_bitmap_init_next_nodes (vm, acl_in_node.index, L2INPUT_N_FEAT,
1855                                l2input_get_feat_names (),
1856                                am->acl_in_node_input_next_node_index);
1857
1858   memset (&am->acl_in_ip4_match_next[0], 0,
1859           sizeof (am->acl_in_ip4_match_next));
1860   memset (&am->acl_in_ip6_match_next[0], 0,
1861           sizeof (am->acl_in_ip6_match_next));
1862   memset (&am->acl_out_ip4_match_next[0], 0,
1863           sizeof (am->acl_out_ip4_match_next));
1864   memset (&am->acl_out_ip6_match_next[0], 0,
1865           sizeof (am->acl_out_ip6_match_next));
1866   am->n_match_actions = 0;
1867
1868   register_match_action_nexts (0, 0, 0, 0);     /* drop */
1869   register_match_action_nexts (~0, ~0, ~0, ~0); /* permit */
1870   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 */
1871 }
1872
1873
1874
1875 static clib_error_t *
1876 acl_init (vlib_main_t * vm)
1877 {
1878   acl_main_t *am = &acl_main;
1879   clib_error_t *error = 0;
1880   memset (am, 0, sizeof (*am));
1881   am->vlib_main = vm;
1882   am->vnet_main = vnet_get_main ();
1883
1884   u8 *name = format (0, "acl_%08x%c", api_version, 0);
1885
1886   /* Ask for a correctly-sized block of API message decode slots */
1887   am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
1888                                             VL_MSG_FIRST_AVAILABLE);
1889
1890   error = acl_plugin_api_hookup (vm);
1891   acl_setup_nodes ();
1892
1893  /* Add our API messages to the global name_crc hash table */
1894   setup_message_id_table (am, &api_main);
1895
1896   vec_free (name);
1897
1898   return error;
1899 }
1900
1901 VLIB_INIT_FUNCTION (acl_init);