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