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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
22 #include <vnet/l2/l2_classify.h>
23 #include <vnet/classify/in_out_acl.h>
24 #include <vpp/app/version.h>
26 #include <vlibapi/api.h>
27 #include <vlibmemory/api.h>
29 /* define message IDs */
30 #include <acl/acl_msg_enum.h>
32 /* define message structures */
34 #include <acl/acl_all_api_h.h>
37 /* define generated endian-swappers */
39 #include <acl/acl_all_api_h.h>
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #include <acl/acl_all_api_h.h>
48 /* Get the API version number */
49 #define vl_api_version(n,v) static u32 api_version=(v);
50 #include <acl/acl_all_api_h.h>
54 #include "hash_lookup.h"
58 #define REPLY_MSG_ID_BASE am->msg_id_base
59 #include <vlibapi/api_helper_macros.h>
61 /* List of message types that this plugin understands */
63 #define foreach_acl_plugin_api_msg \
64 _(ACL_PLUGIN_GET_VERSION, acl_plugin_get_version) \
65 _(ACL_PLUGIN_CONTROL_PING, acl_plugin_control_ping) \
66 _(ACL_ADD_REPLACE, acl_add_replace) \
68 _(ACL_INTERFACE_ADD_DEL, acl_interface_add_del) \
69 _(ACL_INTERFACE_SET_ACL_LIST, acl_interface_set_acl_list) \
70 _(ACL_DUMP, acl_dump) \
71 _(ACL_INTERFACE_LIST_DUMP, acl_interface_list_dump) \
72 _(MACIP_ACL_ADD, macip_acl_add) \
73 _(MACIP_ACL_ADD_REPLACE, macip_acl_add_replace) \
74 _(MACIP_ACL_DEL, macip_acl_del) \
75 _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \
76 _(MACIP_ACL_DUMP, macip_acl_dump) \
77 _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) \
78 _(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump) \
79 _(ACL_INTERFACE_SET_ETYPE_WHITELIST, acl_interface_set_etype_whitelist) \
80 _(ACL_INTERFACE_ETYPE_WHITELIST_DUMP, acl_interface_etype_whitelist_dump)
84 VLIB_PLUGIN_REGISTER () = {
85 .version = VPP_BUILD_VER,
86 .description = "Access Control Lists",
92 format_vec16 (u8 * s, va_list * va)
94 u16 *v = va_arg (*va, u16 *);
95 char *fmt = va_arg (*va, char *);
97 for (i = 0; i < vec_len (v); i++)
100 s = format (s, ", ");
101 s = format (s, fmt, v[i]);
110 acl_set_heap (acl_main_t * am)
112 if (0 == am->acl_mheap)
114 am->acl_mheap = mheap_alloc (0 /* use VM */ , am->acl_mheap_size);
115 mheap_t *h = mheap_header (am->acl_mheap);
116 h->flags |= MHEAP_FLAG_THREAD_SAFE;
118 void *oldheap = clib_mem_set_heap (am->acl_mheap);
123 acl_plugin_acl_set_validate_heap (acl_main_t * am, int on)
125 clib_mem_set_heap (acl_set_heap (am));
126 mheap_t *h = mheap_header (am->acl_mheap);
129 h->flags |= MHEAP_FLAG_VALIDATE;
130 h->flags &= ~MHEAP_FLAG_SMALL_OBJECT_CACHE;
135 h->flags &= ~MHEAP_FLAG_VALIDATE;
136 h->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
141 acl_plugin_acl_set_trace_heap (acl_main_t * am, int on)
143 clib_mem_set_heap (acl_set_heap (am));
144 mheap_t *h = mheap_header (am->acl_mheap);
147 h->flags |= MHEAP_FLAG_TRACE;
151 h->flags &= ~MHEAP_FLAG_TRACE;
156 vl_api_acl_plugin_get_version_t_handler (vl_api_acl_plugin_get_version_t * mp)
158 acl_main_t *am = &acl_main;
159 vl_api_acl_plugin_get_version_reply_t *rmp;
160 int msg_size = sizeof (*rmp);
161 vl_api_registration_t *reg;
163 reg = vl_api_client_index_to_registration (mp->client_index);
167 rmp = vl_msg_api_alloc (msg_size);
168 memset (rmp, 0, msg_size);
170 ntohs (VL_API_ACL_PLUGIN_GET_VERSION_REPLY + am->msg_id_base);
171 rmp->context = mp->context;
172 rmp->major = htonl (ACL_PLUGIN_VERSION_MAJOR);
173 rmp->minor = htonl (ACL_PLUGIN_VERSION_MINOR);
175 vl_api_send_msg (reg, (u8 *) rmp);
179 vl_api_acl_plugin_control_ping_t_handler (vl_api_acl_plugin_control_ping_t *
182 vl_api_acl_plugin_control_ping_reply_t *rmp;
183 acl_main_t *am = &acl_main;
187 REPLY_MACRO2 (VL_API_ACL_PLUGIN_CONTROL_PING_REPLY,
189 rmp->vpe_pid = ntohl (getpid ());
195 acl_add_list (u32 count, vl_api_acl_rule_t rules[],
196 u32 * acl_list_index, u8 * tag)
198 acl_main_t *am = &acl_main;
201 acl_rule_t *acl_new_rules = 0;
204 if (*acl_list_index != ~0)
206 /* They supplied some number, let's see if this ACL exists */
207 if (pool_is_free_index (am->acls, *acl_list_index))
209 /* tried to replace a non-existent ACL, no point doing anything */
211 ("acl-plugin-error: Trying to replace nonexistent ACL %d (tag %s)",
212 *acl_list_index, tag);
213 return VNET_API_ERROR_NO_SUCH_ENTRY;
219 ("acl-plugin-warning: supplied no rules for ACL %d (tag %s)",
220 *acl_list_index, tag);
223 void *oldheap = acl_set_heap (am);
225 /* Create and populate the rules */
227 vec_validate (acl_new_rules, count - 1);
229 for (i = 0; i < count; i++)
231 r = vec_elt_at_index (acl_new_rules, i);
232 memset (r, 0, sizeof (*r));
233 r->is_permit = rules[i].is_permit;
234 r->is_ipv6 = rules[i].is_ipv6;
237 memcpy (&r->src, rules[i].src_ip_addr, sizeof (r->src));
238 memcpy (&r->dst, rules[i].dst_ip_addr, sizeof (r->dst));
242 memcpy (&r->src.ip4, rules[i].src_ip_addr, sizeof (r->src.ip4));
243 memcpy (&r->dst.ip4, rules[i].dst_ip_addr, sizeof (r->dst.ip4));
245 r->src_prefixlen = rules[i].src_ip_prefix_len;
246 r->dst_prefixlen = rules[i].dst_ip_prefix_len;
247 r->proto = rules[i].proto;
248 r->src_port_or_type_first = ntohs (rules[i].srcport_or_icmptype_first);
249 r->src_port_or_type_last = ntohs (rules[i].srcport_or_icmptype_last);
250 r->dst_port_or_code_first = ntohs (rules[i].dstport_or_icmpcode_first);
251 r->dst_port_or_code_last = ntohs (rules[i].dstport_or_icmpcode_last);
252 r->tcp_flags_value = rules[i].tcp_flags_value;
253 r->tcp_flags_mask = rules[i].tcp_flags_mask;
256 if (~0 == *acl_list_index)
259 pool_get_aligned (am->acls, a, CLIB_CACHE_LINE_BYTES);
260 memset (a, 0, sizeof (*a));
261 /* Will return the newly allocated ACL index */
262 *acl_list_index = a - am->acls;
266 a = am->acls + *acl_list_index;
267 hash_acl_delete (am, *acl_list_index);
268 /* Get rid of the old rules */
272 a->rules = acl_new_rules;
274 memcpy (a->tag, tag, sizeof (a->tag));
275 hash_acl_add (am, *acl_list_index);
276 clib_mem_set_heap (oldheap);
281 acl_del_list (u32 acl_list_index)
283 acl_main_t *am = &acl_main;
286 if (pool_is_free_index (am->acls, acl_list_index))
288 return VNET_API_ERROR_NO_SUCH_ENTRY;
291 if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
293 if (vec_len (vec_elt (am->input_sw_if_index_vec_by_acl, acl_list_index))
296 /* ACL is applied somewhere inbound. Refuse to delete */
297 return VNET_API_ERROR_ACL_IN_USE_INBOUND;
300 if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
303 (vec_elt (am->output_sw_if_index_vec_by_acl, acl_list_index)) > 0)
305 /* ACL is applied somewhere outbound. Refuse to delete */
306 return VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
310 void *oldheap = acl_set_heap (am);
311 /* delete any references to the ACL */
312 for (i = 0; i < vec_len (am->output_acl_vec_by_sw_if_index); i++)
314 for (ii = 0; ii < vec_len (am->output_acl_vec_by_sw_if_index[i]);
317 if (acl_list_index == am->output_acl_vec_by_sw_if_index[i][ii])
319 vec_del1 (am->output_acl_vec_by_sw_if_index[i], ii);
327 for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index); i++)
329 for (ii = 0; ii < vec_len (am->input_acl_vec_by_sw_if_index[i]);
332 if (acl_list_index == am->input_acl_vec_by_sw_if_index[i][ii])
334 vec_del1 (am->input_acl_vec_by_sw_if_index[i], ii);
342 /* delete the hash table data */
344 hash_acl_delete (am, acl_list_index);
345 /* now we can delete the ACL itself */
346 a = pool_elt_at_index (am->acls, acl_list_index);
350 pool_put (am->acls, a);
351 clib_mem_set_heap (oldheap);
355 /* Some aids in ASCII graphing the content */
362 u8 ip4_5tuple_mask[] =
363 _(" dmac smac etype ")
364 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
371 _(" ttl pr checksum ")
380 _("L4 T/U sport dport ")
390 u8 ip6_5tuple_mask[] =
391 _(" dmac smac etype ")
392 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v
394 _(0x0000) __ __ __ __
396 _(0x0004) __ __ XX __
398 _(0x0008) XX XX XX XX
399 _(0x000C) XX XX XX XX
400 _(0x0010) XX XX XX XX
401 _(0x0014) XX XX XX XX
403 _(0x0018) XX XX XX XX
404 _(0x001C) XX XX XX XX
405 _(0x0020) XX XX XX XX
406 _(0x0024) XX XX XX XX
407 _("L4T/U sport dport ")
408 _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __;
410 u8 dot1q_5tuple_mask[] =
411 _(" dmac smac dot1q etype ")
412 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __ v XX XX v
413 _(padpad) __ __ __ __
414 _(padpad) __ __ __ __
415 _(padpad) __ __ __ __
418 u8 dot1ad_5tuple_mask[] =
419 _(" dmac smac dot1ad dot1q etype ")
420 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __ XX XX __ __ v XX XX v
421 _(padpad) __ __ __ __
422 _(padpad) __ __ __ __
425 u8 ethertype_mask[] =
426 _(" dmac smac etype ")
427 _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __;
436 count_skip (u8 * p, u32 size)
438 u64 *p64 = (u64 *) p;
439 /* Be tolerant to null pointer */
443 while ((0ULL == *p64) && ((u8 *) p64 - p) < size)
447 return (p64 - (u64 *) p) / 2;
451 acl_classify_add_del_table_tiny (vnet_classify_main_t * cm, u8 * mask,
452 u32 mask_len, u32 next_table_index,
453 u32 miss_next_index, u32 * table_index,
457 u32 memory_size = 2 << 13;
458 u32 skip = count_skip (mask, mask_len);
459 u32 match = (mask_len / 16) - skip;
460 u8 *skip_mask_ptr = mask + 16 * skip;
461 u32 current_data_flag = 0;
462 int current_data_offset = 0;
466 void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
467 int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
468 memory_size, skip, match,
469 next_table_index, miss_next_index,
470 table_index, current_data_flag,
471 current_data_offset, is_add,
472 1 /* delete_chain */ );
473 clib_mem_set_heap (oldheap);
478 acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask,
479 u32 mask_len, u32 next_table_index,
480 u32 miss_next_index, u32 * table_index,
484 u32 memory_size = 2 << 22;
485 u32 skip = count_skip (mask, mask_len);
486 u32 match = (mask_len / 16) - skip;
487 u8 *skip_mask_ptr = mask + 16 * skip;
488 u32 current_data_flag = 0;
489 int current_data_offset = 0;
494 void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base);
495 int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets,
496 memory_size, skip, match,
497 next_table_index, miss_next_index,
498 table_index, current_data_flag,
499 current_data_offset, is_add,
500 1 /* delete_chain */ );
501 clib_mem_set_heap (oldheap);
506 acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
508 vnet_classify_main_t *cm = &vnet_classify_main;
509 u32 ip4_table_index = ~0;
510 u32 ip6_table_index = ~0;
511 u32 dot1q_table_index = ~0;
512 u32 dot1ad_table_index = ~0;
513 u32 etype_table_index = ~0;
514 void *oldheap = acl_set_heap (am);
516 vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index,
518 vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index,
520 vec_validate_init_empty (am->acl_dot1q_input_classify_table_by_sw_if_index,
522 vec_validate_init_empty (am->acl_dot1ad_input_classify_table_by_sw_if_index,
524 vec_validate_init_empty (am->acl_etype_input_classify_table_by_sw_if_index,
527 /* switch to global heap while calling vnet_* functions */
528 clib_mem_set_heap (cm->vlib_main->heap_base);
529 vnet_l2_input_classify_enable_disable (sw_if_index, 0);
531 if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
534 am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index];
535 am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
536 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
537 sizeof (ip4_5tuple_mask) - 1, ~0,
538 am->l2_input_classify_next_acl_ip4,
539 &ip4_table_index, 0);
541 if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
544 am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index];
545 am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
546 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
547 sizeof (ip6_5tuple_mask) - 1, ~0,
548 am->l2_input_classify_next_acl_ip6,
549 &ip6_table_index, 0);
551 if (am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
554 am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index];
555 am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
556 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
557 sizeof (ip6_5tuple_mask) - 1, ~0,
558 ~0, &dot1q_table_index, 0);
560 if (am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
563 am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index];
564 am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
565 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
566 sizeof (dot1ad_5tuple_mask) - 1, ~0,
567 ~0, &dot1ad_table_index, 0);
569 if (am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] != ~0)
572 am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index];
573 am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] = ~0;
574 acl_classify_add_del_table_tiny (cm, ethertype_mask,
575 sizeof (ethertype_mask) - 1, ~0,
576 ~0, &etype_table_index, 0);
578 clib_mem_set_heap (oldheap);
583 acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
585 vnet_classify_main_t *cm = &vnet_classify_main;
586 u32 ip4_table_index = ~0;
587 u32 ip6_table_index = ~0;
588 u32 dot1q_table_index = ~0;
589 u32 dot1ad_table_index = ~0;
590 u32 etype_table_index = ~0;
591 void *oldheap = acl_set_heap (am);
593 vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index,
595 vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index,
597 vec_validate_init_empty (am->acl_dot1q_output_classify_table_by_sw_if_index,
599 vec_validate_init_empty
600 (am->acl_dot1ad_output_classify_table_by_sw_if_index, sw_if_index, ~0);
601 vec_validate_init_empty (am->acl_etype_output_classify_table_by_sw_if_index,
604 /* switch to global heap while calling vnet_* functions */
605 clib_mem_set_heap (cm->vlib_main->heap_base);
607 vnet_l2_output_classify_enable_disable (sw_if_index, 0);
609 if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
612 am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index];
613 am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
614 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
615 sizeof (ip4_5tuple_mask) - 1, ~0,
616 am->l2_output_classify_next_acl_ip4,
617 &ip4_table_index, 0);
619 if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
622 am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index];
623 am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
624 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
625 sizeof (ip6_5tuple_mask) - 1, ~0,
626 am->l2_output_classify_next_acl_ip6,
627 &ip6_table_index, 0);
629 if (am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
632 am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index];
633 am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
634 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
635 sizeof (ip6_5tuple_mask) - 1, ~0,
636 ~0, &dot1q_table_index, 0);
638 if (am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
641 am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index];
642 am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
643 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
644 sizeof (dot1ad_5tuple_mask) - 1, ~0,
645 ~0, &dot1ad_table_index, 0);
647 if (am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] != ~0)
650 am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index];
651 am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] = ~0;
652 acl_classify_add_del_table_tiny (cm, ethertype_mask,
653 sizeof (ethertype_mask) - 1, ~0,
654 ~0, &etype_table_index, 0);
656 clib_mem_set_heap (oldheap);
661 acl_add_vlan_session (acl_main_t * am, u32 table_index, u8 is_output,
662 u8 is_dot1ad, u8 is_ip6)
664 vnet_classify_main_t *cm = &vnet_classify_main;
674 l2_output_classify_next_acl_ip6 : am->l2_input_classify_next_acl_ip6;
680 l2_output_classify_next_acl_ip4 : am->l2_input_classify_next_acl_ip4;
682 match = (is_dot1ad) ? dot1ad_5tuple_mask : dot1q_5tuple_mask;
683 idx = (is_dot1ad) ? 20 : 16;
686 /* 802.1ad ethertype */
689 /* 802.1q ethertype */
695 /* 802.1q ethertype */
700 /* add sessions to vlan tables per ethernet_type */
704 match[idx + 1] = 0xdd;
710 match[idx + 1] = 0x00;
713 vnet_classify_add_del_session (cm, table_index, match, next_acl,
714 session_idx, 0, 0, 0, 1);
715 /* reset the mask back to being a mask */
717 match[idx + 1] = 0xff;
728 intf_has_etype_whitelist (acl_main_t * am, u32 sw_if_index, int is_input)
731 ? am->input_etype_whitelist_by_sw_if_index
732 : am->output_etype_whitelist_by_sw_if_index;
733 return ((vec_len (v) > sw_if_index) && vec_elt (v, sw_if_index));
737 etype_whitelist_add_sessions (acl_main_t * am, u32 sw_if_index, int is_input,
738 u32 etype_table_index)
740 vnet_classify_main_t *cm = &vnet_classify_main;
742 ? am->input_etype_whitelist_by_sw_if_index
743 : am->output_etype_whitelist_by_sw_if_index;
744 u8 *match = ethertype_mask;
748 u16 *whitelist = vec_elt (v, sw_if_index);
749 u32 next = ~0; /* permit */
750 for (i = 0; i < vec_len (whitelist); i++)
753 match[12] = (whitelist[i] >> 8) & 0xff;
754 match[13] = whitelist[i] & 0xff;
756 || vnet_classify_add_del_session (cm, etype_table_index, match, next,
757 whitelist[i], 0, 0, 0, 1);
760 /* restore the mask */
767 acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index)
769 vnet_classify_main_t *cm = &vnet_classify_main;
770 u32 ip4_table_index = ~0;
771 u32 ip6_table_index = ~0;
772 u32 dot1q_table_index = ~0;
773 u32 dot1ad_table_index = ~0;
774 u32 etype_table_index = ~0;
777 void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
779 /* in case there were previous tables attached */
780 acl_unhook_l2_input_classify (am, sw_if_index);
782 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
783 sizeof (ip4_5tuple_mask) - 1, ~0,
784 am->l2_input_classify_next_acl_ip4,
785 &ip4_table_index, 1);
790 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
791 sizeof (ip6_5tuple_mask) - 1, ~0,
792 am->l2_input_classify_next_acl_ip6,
793 &ip6_table_index, 1);
796 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
797 sizeof (ip4_5tuple_mask) - 1, ~0,
798 am->l2_input_classify_next_acl_ip4,
799 &ip4_table_index, 0);
803 if (intf_has_etype_whitelist (am, sw_if_index, 1))
805 acl_classify_add_del_table_tiny (cm, ethertype_mask, sizeof (ethertype_mask) - 1, ~0, 0, /* drop if no match */
806 &etype_table_index, 1);
807 etype_whitelist_add_sessions (am, sw_if_index, 1, etype_table_index);
811 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
812 sizeof (dot1ad_5tuple_mask) - 1,
813 etype_table_index, ~0,
814 &dot1ad_table_index, 1);
816 acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
817 sizeof (dot1q_5tuple_mask) - 1,
818 dot1ad_table_index, ~0,
819 &dot1q_table_index, 1);
822 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
823 sizeof (dot1ad_5tuple_mask) - 1, ~0,
824 ~0, &dot1ad_table_index, 0);
825 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
826 sizeof (ip6_5tuple_mask) - 1, ~0,
827 am->l2_input_classify_next_acl_ip6,
828 &ip6_table_index, 0);
829 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
830 sizeof (ip4_5tuple_mask) - 1, ~0,
831 am->l2_input_classify_next_acl_ip4,
832 &ip4_table_index, 0);
837 vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index,
838 ip6_table_index, dot1q_table_index);
842 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
843 sizeof (ip4_5tuple_mask) - 1, ~0,
844 am->l2_input_classify_next_acl_ip4,
845 &ip4_table_index, 0);
846 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
847 sizeof (ip6_5tuple_mask) - 1, ~0,
848 am->l2_input_classify_next_acl_ip6,
849 &ip6_table_index, 0);
850 acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
851 sizeof (dot1q_5tuple_mask) - 1, ~0,
852 ~0, &dot1q_table_index, 0);
853 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
854 sizeof (dot1ad_5tuple_mask) - 1, ~0,
855 ~0, &dot1ad_table_index, 0);
859 /* add sessions to vlan tables per ethernet_type */
860 acl_add_vlan_session (am, dot1q_table_index, 0, 0, 0);
861 acl_add_vlan_session (am, dot1q_table_index, 0, 0, 1);
862 acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 0);
863 acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 1);
865 am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] =
867 am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] =
869 am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] =
871 am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] =
873 am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] =
875 am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] =
878 vnet_l2_input_classify_enable_disable (sw_if_index, 1);
880 clib_mem_set_heap (prevheap);
885 acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index)
887 vnet_classify_main_t *cm = &vnet_classify_main;
888 u32 ip4_table_index = ~0;
889 u32 ip6_table_index = ~0;
890 u32 dot1q_table_index = ~0;
891 u32 dot1ad_table_index = ~0;
892 u32 etype_table_index = ~0;
895 void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base);
897 /* in case there were previous tables attached */
898 acl_unhook_l2_output_classify (am, sw_if_index);
900 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
901 sizeof (ip4_5tuple_mask) - 1, ~0,
902 am->l2_output_classify_next_acl_ip4,
903 &ip4_table_index, 1);
907 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
908 sizeof (ip6_5tuple_mask) - 1, ~0,
909 am->l2_output_classify_next_acl_ip6,
910 &ip6_table_index, 1);
913 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
914 sizeof (ip4_5tuple_mask) - 1, ~0,
915 am->l2_output_classify_next_acl_ip4,
916 &ip4_table_index, 0);
920 if (intf_has_etype_whitelist (am, sw_if_index, 0))
922 acl_classify_add_del_table_tiny (cm, ethertype_mask, sizeof (ethertype_mask) - 1, ~0, 0, /* drop if no match */
923 &etype_table_index, 1);
924 etype_whitelist_add_sessions (am, sw_if_index, 0, etype_table_index);
929 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
930 sizeof (dot1ad_5tuple_mask) - 1,
931 etype_table_index, ~0,
932 &dot1ad_table_index, 1);
934 acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
935 sizeof (dot1q_5tuple_mask) - 1,
936 dot1ad_table_index, ~0,
937 &dot1q_table_index, 1);
940 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
941 sizeof (dot1ad_5tuple_mask) - 1, ~0,
942 ~0, &dot1ad_table_index, 0);
943 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
944 sizeof (ip6_5tuple_mask) - 1, ~0,
945 am->l2_output_classify_next_acl_ip6,
946 &ip6_table_index, 0);
947 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
948 sizeof (ip4_5tuple_mask) - 1, ~0,
949 am->l2_output_classify_next_acl_ip4,
950 &ip4_table_index, 0);
955 vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index,
956 ip6_table_index, dot1q_table_index);
959 ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n",
960 sw_if_index, ip4_table_index, ip6_table_index);
963 acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask,
964 sizeof (ip6_5tuple_mask) - 1, ~0,
965 am->l2_output_classify_next_acl_ip6,
966 &ip6_table_index, 0);
967 acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask,
968 sizeof (ip4_5tuple_mask) - 1, ~0,
969 am->l2_output_classify_next_acl_ip4,
970 &ip4_table_index, 0);
971 acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask,
972 sizeof (dot1q_5tuple_mask) - 1, ~0,
973 ~0, &dot1q_table_index, 0);
974 acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask,
975 sizeof (dot1ad_5tuple_mask) - 1, ~0,
976 ~0, &dot1ad_table_index, 0);
980 /* add sessions to vlan tables per ethernet_type */
981 acl_add_vlan_session (am, dot1q_table_index, 1, 0, 0);
982 acl_add_vlan_session (am, dot1q_table_index, 1, 0, 1);
983 acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 0);
984 acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 1);
986 am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] =
988 am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] =
990 am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] =
992 am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] =
994 am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] =
997 vnet_l2_output_classify_enable_disable (sw_if_index, 1);
999 clib_mem_set_heap (prevheap);
1004 acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index,
1009 /* Utterly wrong? */
1010 if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
1012 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1014 acl_fa_enable_disable (sw_if_index, 1, enable_disable);
1018 rv = acl_hook_l2_input_classify (am, sw_if_index);
1022 rv = acl_unhook_l2_input_classify (am, sw_if_index);
1029 acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index,
1034 /* Utterly wrong? */
1035 if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces,
1037 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1039 acl_fa_enable_disable (sw_if_index, 0, enable_disable);
1043 rv = acl_hook_l2_output_classify (am, sw_if_index);
1047 rv = acl_unhook_l2_output_classify (am, sw_if_index);
1054 acl_is_not_defined (acl_main_t * am, u32 acl_list_index)
1056 return (pool_is_free_index (am->acls, acl_list_index));
1061 acl_interface_add_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
1063 acl_main_t *am = &acl_main;
1064 if (acl_is_not_defined (am, acl_list_index))
1066 /* ACL is not defined. Can not apply */
1067 return VNET_API_ERROR_NO_SUCH_ENTRY;
1069 void *oldheap = acl_set_heap (am);
1073 vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1075 u32 index = vec_search (am->input_acl_vec_by_sw_if_index[sw_if_index],
1077 if (index < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
1080 ("ACL %d is already applied inbound on sw_if_index %d (index %d)",
1081 acl_list_index, sw_if_index, index);
1082 /* the entry is already there */
1083 clib_mem_set_heap (oldheap);
1084 return VNET_API_ERROR_ACL_IN_USE_INBOUND;
1086 /* if there was no ACL applied before, enable the ACL processing */
1087 if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) == 0)
1089 acl_interface_in_enable_disable (am, sw_if_index, 1);
1091 vec_add (am->input_acl_vec_by_sw_if_index[sw_if_index], &acl_list_index,
1093 vec_validate (am->input_sw_if_index_vec_by_acl, acl_list_index);
1094 vec_add (am->input_sw_if_index_vec_by_acl[acl_list_index], &sw_if_index,
1099 vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1101 u32 index = vec_search (am->output_acl_vec_by_sw_if_index[sw_if_index],
1103 if (index < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
1106 ("ACL %d is already applied outbound on sw_if_index %d (index %d)",
1107 acl_list_index, sw_if_index, index);
1108 /* the entry is already there */
1109 clib_mem_set_heap (oldheap);
1110 return VNET_API_ERROR_ACL_IN_USE_OUTBOUND;
1112 /* if there was no ACL applied before, enable the ACL processing */
1113 if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) == 0)
1115 acl_interface_out_enable_disable (am, sw_if_index, 1);
1117 vec_add (am->output_acl_vec_by_sw_if_index[sw_if_index],
1118 &acl_list_index, 1);
1119 vec_validate (am->output_sw_if_index_vec_by_acl, acl_list_index);
1120 vec_add (am->output_sw_if_index_vec_by_acl[acl_list_index],
1123 clib_mem_set_heap (oldheap);
1129 acl_interface_del_inout_acl (u32 sw_if_index, u8 is_input, u32 acl_list_index)
1131 acl_main_t *am = &acl_main;
1133 int rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1134 void *oldheap = acl_set_heap (am);
1137 vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1138 for (i = 0; i < vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1141 if (acl_list_index ==
1142 am->input_acl_vec_by_sw_if_index[sw_if_index][i])
1144 vec_del1 (am->input_acl_vec_by_sw_if_index[sw_if_index], i);
1150 if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
1153 vec_search (am->input_sw_if_index_vec_by_acl[acl_list_index],
1156 vec_len (am->input_sw_if_index_vec_by_acl[acl_list_index]))
1158 hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1159 vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index],
1164 /* If there is no more ACLs applied on an interface, disable ACL processing */
1165 if (0 == vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]))
1167 acl_interface_in_enable_disable (am, sw_if_index, 0);
1172 vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1174 i < vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]); i++)
1176 if (acl_list_index ==
1177 am->output_acl_vec_by_sw_if_index[sw_if_index][i])
1179 vec_del1 (am->output_acl_vec_by_sw_if_index[sw_if_index], i);
1185 if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
1188 vec_search (am->output_sw_if_index_vec_by_acl[acl_list_index],
1191 vec_len (am->output_sw_if_index_vec_by_acl[acl_list_index]))
1193 hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1194 vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index],
1199 /* If there is no more ACLs applied on an interface, disable ACL processing */
1200 if (0 == vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]))
1202 acl_interface_out_enable_disable (am, sw_if_index, 0);
1205 clib_mem_set_heap (oldheap);
1210 acl_interface_reset_inout_acls (u32 sw_if_index, u8 is_input)
1212 acl_main_t *am = &acl_main;
1214 void *oldheap = acl_set_heap (am);
1217 vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
1218 if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1220 acl_interface_in_enable_disable (am, sw_if_index, 0);
1223 for (i = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) - 1;
1226 u32 acl_list_index =
1227 am->input_acl_vec_by_sw_if_index[sw_if_index][i];
1228 hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1229 if (acl_list_index < vec_len (am->input_sw_if_index_vec_by_acl))
1232 vec_search (am->input_sw_if_index_vec_by_acl[acl_list_index],
1235 vec_len (am->input_sw_if_index_vec_by_acl[acl_list_index]))
1237 vec_del1 (am->input_sw_if_index_vec_by_acl[acl_list_index],
1243 vec_reset_length (am->input_acl_vec_by_sw_if_index[sw_if_index]);
1247 vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
1248 if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1250 acl_interface_out_enable_disable (am, sw_if_index, 0);
1253 for (i = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) - 1;
1256 u32 acl_list_index =
1257 am->output_acl_vec_by_sw_if_index[sw_if_index][i];
1258 hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1259 if (acl_list_index < vec_len (am->output_sw_if_index_vec_by_acl))
1262 vec_search (am->output_sw_if_index_vec_by_acl[acl_list_index],
1265 vec_len (am->output_sw_if_index_vec_by_acl[acl_list_index]))
1267 vec_del1 (am->output_sw_if_index_vec_by_acl[acl_list_index],
1273 vec_reset_length (am->output_acl_vec_by_sw_if_index[sw_if_index]);
1275 clib_mem_set_heap (oldheap);
1279 acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input,
1282 int rv = VNET_API_ERROR_NO_SUCH_ENTRY;
1283 acl_main_t *am = &acl_main;
1287 acl_interface_add_inout_acl (sw_if_index, is_input, acl_list_index);
1290 hash_acl_apply (am, sw_if_index, is_input, acl_list_index);
1295 hash_acl_unapply (am, sw_if_index, is_input, acl_list_index);
1297 acl_interface_del_inout_acl (sw_if_index, is_input, acl_list_index);
1303 acl_set_etype_whitelists (acl_main_t * am, u32 sw_if_index, u16 * vec_in,
1306 vec_validate (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
1307 vec_validate (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
1309 vec_free (am->input_etype_whitelist_by_sw_if_index[sw_if_index]);
1310 vec_free (am->output_etype_whitelist_by_sw_if_index[sw_if_index]);
1312 am->input_etype_whitelist_by_sw_if_index[sw_if_index] = vec_in;
1313 am->output_etype_whitelist_by_sw_if_index[sw_if_index] = vec_out;
1316 * if there are already inbound/outbound ACLs applied, toggle the
1317 * enable/disable - this will recreate the necessary tables.
1320 if (vec_len (am->input_acl_vec_by_sw_if_index) > sw_if_index)
1322 if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1324 acl_interface_in_enable_disable (am, sw_if_index, 0);
1325 acl_interface_in_enable_disable (am, sw_if_index, 1);
1328 if (vec_len (am->output_acl_vec_by_sw_if_index) > sw_if_index)
1330 if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0)
1332 acl_interface_out_enable_disable (am, sw_if_index, 0);
1333 acl_interface_out_enable_disable (am, sw_if_index, 1);
1348 u32 arp_table_index;
1349 u32 dot1q_table_index;
1350 u32 dot1ad_table_index;
1352 u32 out_table_index;
1353 u32 out_arp_table_index;
1354 u32 out_dot1q_table_index;
1355 u32 out_dot1ad_table_index;
1356 } macip_match_type_t;
1359 macip_find_match_type (macip_match_type_t * mv, u8 * mac_mask, u8 prefix_len,
1365 for (i = 0; i < vec_len (mv); i++)
1367 if ((mv[i].prefix_len == prefix_len) && (mv[i].is_ipv6 == is_ipv6)
1368 && (0 == memcmp (mv[i].mac_mask, mac_mask, 6)))
1378 /* Get metric used to sort match types.
1379 The more specific and the more often seen - the bigger the metric */
1381 match_type_metric (macip_match_type_t * m)
1383 unsigned int mac_bits_set = 0;
1384 unsigned int mac_byte;
1386 for (i = 0; i < 6; i++)
1388 mac_byte = m->mac_mask[i];
1389 for (; mac_byte; mac_byte >>= 1)
1390 mac_bits_set += mac_byte & 1;
1393 * Attempt to place the more specific and the more used rules on top.
1394 * There are obvious caveat corner cases to this, but they do not
1395 * seem to be sensible in real world (e.g. specific IPv4 with wildcard MAC
1396 * going with a wildcard IPv4 with a specific MAC).
1398 return m->prefix_len + mac_bits_set + m->is_ipv6 + 10 * m->count;
1402 match_type_compare (macip_match_type_t * m1, macip_match_type_t * m2)
1404 /* Ascending sort based on the metric values */
1405 return match_type_metric (m1) - match_type_metric (m2);
1408 /* Get the offset of L3 source within ethernet packet */
1410 get_l3_src_offset (int is6)
1413 return (sizeof (ethernet_header_t) +
1414 offsetof (ip6_header_t, src_address));
1416 return (sizeof (ethernet_header_t) +
1417 offsetof (ip4_header_t, src_address));
1421 get_l3_dst_offset (int is6)
1424 return (sizeof (ethernet_header_t) +
1425 offsetof (ip6_header_t, dst_address));
1427 return (sizeof (ethernet_header_t) +
1428 offsetof (ip4_header_t, dst_address));
1432 * return if the is_permit value also requires to create the egress tables
1433 * For backwards compatibility, we keep the is_permit = 1 to only
1434 * create the ingress tables, and the new value of 3 will also
1435 * create the egress tables based on destination.
1438 macip_permit_also_egress (u8 is_permit)
1440 return (is_permit == 3);
1444 macip_create_classify_tables (acl_main_t * am, u32 macip_acl_index)
1446 macip_match_type_t *mvec = NULL;
1447 macip_match_type_t *mt;
1448 macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1450 u32 match_type_index;
1454 vnet_classify_main_t *cm = &vnet_classify_main;
1456 /* Count the number of different types of rules */
1457 for (i = 0; i < a->count; i++)
1461 macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1462 a->rules[i].src_prefixlen,
1463 a->rules[i].is_ipv6)))
1465 match_type_index = vec_len (mvec);
1466 vec_validate (mvec, match_type_index);
1467 memcpy (mvec[match_type_index].mac_mask,
1468 a->rules[i].src_mac_mask, 6);
1469 mvec[match_type_index].prefix_len = a->rules[i].src_prefixlen;
1470 mvec[match_type_index].is_ipv6 = a->rules[i].is_ipv6;
1471 mvec[match_type_index].has_egress = 0;
1472 mvec[match_type_index].table_index = ~0;
1473 mvec[match_type_index].arp_table_index = ~0;
1474 mvec[match_type_index].dot1q_table_index = ~0;
1475 mvec[match_type_index].dot1ad_table_index = ~0;
1476 mvec[match_type_index].out_table_index = ~0;
1477 mvec[match_type_index].out_arp_table_index = ~0;
1478 mvec[match_type_index].out_dot1q_table_index = ~0;
1479 mvec[match_type_index].out_dot1ad_table_index = ~0;
1481 mvec[match_type_index].count++;
1482 mvec[match_type_index].has_egress |=
1483 macip_permit_also_egress (a->rules[i].is_permit);
1485 /* Put the most frequently used tables last in the list so we can create classifier tables in reverse order */
1486 vec_sort_with_function (mvec, match_type_compare);
1487 /* Create the classifier tables */
1489 out_last_table = ~0;
1490 /* First add ARP tables */
1491 vec_foreach (mt, mvec)
1494 int is6 = mt->is_ipv6;
1500 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1501 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1502 | Destination Address |
1503 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1505 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
1507 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1508 | EtherType | Hardware Type |
1509 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1510 | Protocol Type | Hw addr len | Proto addr len|
1511 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1513 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
1514 | Sender Hardware Address |
1515 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1516 | Sender Protocol Address |
1517 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1518 | Target Hardware Address |
1519 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1520 | | TargetProtocolAddress |
1521 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1523 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1525 memset (mask, 0, sizeof (mask));
1526 /* source MAC address */
1527 memcpy (&mask[6], mt->mac_mask, 6);
1528 memset (&mask[12], 0xff, 2); /* ethernet protocol */
1529 /* sender hardware address within ARP */
1530 memcpy (&mask[14 + 8], mt->mac_mask, 6);
1531 /* sender protocol address within ARP */
1532 for (i = 0; i < (mt->prefix_len / 8); i++)
1533 mask[14 + 14 + i] = 0xff;
1534 if (mt->prefix_len % 8)
1535 mask[14 + 14 + (mt->prefix_len / 8)] =
1536 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1538 mask_len = ((14 + 14 + ((mt->prefix_len + 7) / 8) +
1539 (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
1540 acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1541 (~0 == last_table) ? 0 : ~0,
1542 &mt->arp_table_index, 1);
1543 last_table = mt->arp_table_index;
1546 /* egress ARP table */
1547 memset (mask, 0, sizeof (mask));
1548 // memcpy (&mask[0], mt->mac_mask, 6);
1549 memset (&mask[12], 0xff, 2); /* ethernet protocol */
1550 /* AYXX: FIXME here - can we tighten the ARP-related table more ? */
1551 /* mask captures just the destination and the ethertype */
1554 1)) / sizeof (u32x4)) * sizeof (u32x4);
1555 acl_classify_add_del_table_small (cm, mask, mask_len,
1557 (~0 == out_last_table) ? 0 : ~0,
1558 &mt->out_arp_table_index, 1);
1559 out_last_table = mt->out_arp_table_index;
1563 /* Now add IP[46] tables */
1564 vec_foreach (mt, mvec)
1567 int is6 = mt->is_ipv6;
1571 u32 *last_tag_table;
1572 u32 *out_last_tag_table;
1575 * create chained tables for VLAN (no-tags, dot1q and dot1ad) packets
1577 for (tags = 2; tags >= 0; tags--)
1579 memset (mask, 0, sizeof (mask));
1580 memcpy (&mask[6], mt->mac_mask, 6);
1581 l3_src_offs = tags * 4 + get_l3_src_offset (is6);
1586 memset (&mask[12], 0xff, 2); /* ethernet protocol */
1587 last_tag_table = &mt->table_index;
1590 memset (&mask[12], 0xff, 2); /* VLAN tag1 */
1591 memset (&mask[16], 0xff, 2); /* ethernet protocol */
1592 last_tag_table = &mt->dot1q_table_index;
1595 memset (&mask[12], 0xff, 2); /* VLAN tag1 */
1596 memset (&mask[16], 0xff, 2); /* VLAN tag2 */
1597 memset (&mask[20], 0xff, 2); /* ethernet protocol */
1598 last_tag_table = &mt->dot1ad_table_index;
1601 for (i = 0; i < (mt->prefix_len / 8); i++)
1603 mask[l3_src_offs + i] = 0xff;
1605 if (mt->prefix_len % 8)
1607 mask[l3_src_offs + (mt->prefix_len / 8)] =
1608 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1611 * Round-up the number of bytes needed to store the prefix,
1612 * and round up the number of vectors too
1614 mask_len = ((l3_src_offs + ((mt->prefix_len + 7) / 8) +
1615 (sizeof (u32x4) - 1)) / sizeof (u32x4)) * sizeof (u32x4);
1616 acl_classify_add_del_table_small (cm, mask, mask_len, last_table,
1617 (~0 == last_table) ? 0 : ~0,
1619 last_table = *last_tag_table;
1623 for (tags = 2; tags >= 0; tags--)
1625 memset (mask, 0, sizeof (mask));
1626 /* MAC destination */
1627 memcpy (&mask[0], mt->mac_mask, 6);
1628 l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
1633 memset (&mask[12], 0xff, 2); /* ethernet protocol */
1634 out_last_tag_table = &mt->out_table_index;
1637 memset (&mask[12], 0xff, 2); /* VLAN tag1 */
1638 memset (&mask[16], 0xff, 2); /* ethernet protocol */
1639 out_last_tag_table = &mt->out_dot1q_table_index;
1642 memset (&mask[12], 0xff, 2); /* VLAN tag1 */
1643 memset (&mask[16], 0xff, 2); /* VLAN tag2 */
1644 memset (&mask[20], 0xff, 2); /* ethernet protocol */
1645 out_last_tag_table = &mt->out_dot1ad_table_index;
1648 for (i = 0; i < (mt->prefix_len / 8); i++)
1650 mask[l3_dst_offs + i] = 0xff;
1652 if (mt->prefix_len % 8)
1654 mask[l3_dst_offs + (mt->prefix_len / 8)] =
1655 0xff - ((1 << (8 - mt->prefix_len % 8)) - 1);
1658 * Round-up the number of bytes needed to store the prefix,
1659 * and round up the number of vectors too
1661 mask_len = ((l3_dst_offs + ((mt->prefix_len + 7) / 8) +
1663 1)) / sizeof (u32x4)) * sizeof (u32x4);
1664 acl_classify_add_del_table_small (cm, mask, mask_len,
1666 (~0 == out_last_table) ? 0 : ~0,
1667 out_last_tag_table, 1);
1668 out_last_table = *out_last_tag_table;
1672 a->ip4_table_index = last_table;
1673 a->ip6_table_index = last_table;
1674 a->l2_table_index = last_table;
1676 a->out_ip4_table_index = out_last_table;
1677 a->out_ip6_table_index = out_last_table;
1678 a->out_l2_table_index = out_last_table;
1680 /* Populate the classifier tables with rules from the MACIP ACL */
1681 for (i = 0; i < a->count; i++)
1685 int is6 = a->rules[i].is_ipv6;
1692 macip_find_match_type (mvec, a->rules[i].src_mac_mask,
1693 a->rules[i].src_prefixlen,
1694 a->rules[i].is_ipv6);
1695 ASSERT (match_type_index != ~0);
1697 for (tags = 2; tags >= 0; tags--)
1699 memset (mask, 0, sizeof (mask));
1700 l3_src_offs = tags * 4 + get_l3_src_offset (is6);
1701 memcpy (&mask[6], a->rules[i].src_mac, 6);
1706 tag_table = mvec[match_type_index].table_index;
1710 tag_table = mvec[match_type_index].dot1q_table_index;
1716 tag_table = mvec[match_type_index].dot1ad_table_index;
1726 memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip6, 16);
1728 mask[eth + 1] = 0xdd;
1732 memcpy (&mask[l3_src_offs], &a->rules[i].src_ip_addr.ip4, 4);
1734 mask[eth + 1] = 0x00;
1737 /* add session to table mvec[match_type_index].table_index; */
1738 vnet_classify_add_del_session (cm, tag_table,
1739 mask, a->rules[i].is_permit ? ~0 : 0,
1740 i, 0, action, metadata, 1);
1741 memset (&mask[12], 0, sizeof (mask) - 12);
1744 /* add ARP table entry too */
1745 if (!is6 && (mvec[match_type_index].arp_table_index != ~0))
1747 memset (mask, 0, sizeof (mask));
1748 memcpy (&mask[6], a->rules[i].src_mac, 6);
1751 memcpy (&mask[14 + 8], a->rules[i].src_mac, 6);
1752 memcpy (&mask[14 + 14], &a->rules[i].src_ip_addr.ip4, 4);
1753 vnet_classify_add_del_session (cm,
1755 [match_type_index].arp_table_index,
1756 mask, a->rules[i].is_permit ? ~0 : 0,
1757 i, 0, action, metadata, 1);
1759 if (macip_permit_also_egress (a->rules[i].is_permit))
1761 /* Add the egress entry with destination set */
1762 for (tags = 2; tags >= 0; tags--)
1764 memset (mask, 0, sizeof (mask));
1765 l3_dst_offs = tags * 4 + get_l3_dst_offset (is6);
1766 /* src mac in the other direction becomes dst */
1767 memcpy (&mask[0], a->rules[i].src_mac, 6);
1772 tag_table = mvec[match_type_index].out_table_index;
1776 tag_table = mvec[match_type_index].out_dot1q_table_index;
1782 tag_table = mvec[match_type_index].out_dot1ad_table_index;
1792 memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip6,
1795 mask[eth + 1] = 0xdd;
1799 memcpy (&mask[l3_dst_offs], &a->rules[i].src_ip_addr.ip4,
1802 mask[eth + 1] = 0x00;
1805 /* add session to table mvec[match_type_index].table_index; */
1806 vnet_classify_add_del_session (cm, tag_table,
1808 a->rules[i].is_permit ? ~0 : 0,
1809 i, 0, action, metadata, 1);
1810 // memset (&mask[12], 0, sizeof (mask) - 12);
1813 /* add ARP table entry too */
1814 if (!is6 && (mvec[match_type_index].out_arp_table_index != ~0))
1816 memset (mask, 0, sizeof (mask));
1817 memcpy (&mask[0], a->rules[i].src_mac, 6);
1820 vnet_classify_add_del_session (cm,
1822 [match_type_index].out_arp_table_index,
1824 a->rules[i].is_permit ? ~0 : 0,
1825 i, 0, action, metadata, 1);
1833 macip_destroy_classify_tables (acl_main_t * am, u32 macip_acl_index)
1835 vnet_classify_main_t *cm = &vnet_classify_main;
1836 macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, macip_acl_index);
1838 if (a->ip4_table_index != ~0)
1840 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1841 &a->ip4_table_index, 0);
1842 a->ip4_table_index = ~0;
1844 if (a->ip6_table_index != ~0)
1846 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1847 &a->ip6_table_index, 0);
1848 a->ip6_table_index = ~0;
1850 if (a->l2_table_index != ~0)
1852 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0, &a->l2_table_index,
1854 a->l2_table_index = ~0;
1856 if (a->out_ip4_table_index != ~0)
1858 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1859 &a->out_ip4_table_index, 0);
1860 a->out_ip4_table_index = ~0;
1862 if (a->out_ip6_table_index != ~0)
1864 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1865 &a->out_ip6_table_index, 0);
1866 a->out_ip6_table_index = ~0;
1868 if (a->out_l2_table_index != ~0)
1870 acl_classify_add_del_table_small (cm, 0, ~0, ~0, ~0,
1871 &a->out_l2_table_index, 0);
1872 a->out_l2_table_index = ~0;
1877 macip_maybe_apply_unapply_classifier_tables (acl_main_t * am, u32 acl_index,
1883 macip_acl_list_t *a = pool_elt_at_index (am->macip_acls, acl_index);
1885 for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
1886 if (vec_elt (am->macip_acl_by_sw_if_index, i) == acl_index)
1888 rv0 = vnet_set_input_acl_intfc (am->vlib_main, i, a->ip4_table_index,
1889 a->ip6_table_index, a->l2_table_index,
1891 /* return the first unhappy outcome but make try to plough through. */
1894 vnet_set_output_acl_intfc (am->vlib_main, i, a->out_ip4_table_index,
1895 a->out_ip6_table_index,
1896 a->out_l2_table_index, is_apply);
1897 /* return the first unhappy outcome but make try to plough through. */
1904 macip_acl_add_list (u32 count, vl_api_macip_acl_rule_t rules[],
1905 u32 * acl_list_index, u8 * tag)
1907 acl_main_t *am = &acl_main;
1908 macip_acl_list_t *a;
1909 macip_acl_rule_t *r;
1910 macip_acl_rule_t *acl_new_rules = 0;
1914 if (*acl_list_index != ~0)
1916 /* They supplied some number, let's see if this MACIP ACL exists */
1917 if (pool_is_free_index (am->macip_acls, *acl_list_index))
1919 /* tried to replace a non-existent ACL, no point doing anything */
1921 ("acl-plugin-error: Trying to replace nonexistent MACIP ACL %d (tag %s)",
1922 *acl_list_index, tag);
1923 return VNET_API_ERROR_NO_SUCH_ENTRY;
1930 ("acl-plugin-warning: Trying to create empty MACIP ACL (tag %s)",
1933 /* if replacing the ACL, unapply the classifier tables first - they will be gone.. */
1934 if (~0 != *acl_list_index)
1935 rv = macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 0);
1936 void *oldheap = acl_set_heap (am);
1937 /* Create and populate the rules */
1939 vec_validate (acl_new_rules, count - 1);
1941 for (i = 0; i < count; i++)
1943 r = &acl_new_rules[i];
1944 r->is_permit = rules[i].is_permit;
1945 r->is_ipv6 = rules[i].is_ipv6;
1946 memcpy (&r->src_mac, rules[i].src_mac, 6);
1947 memcpy (&r->src_mac_mask, rules[i].src_mac_mask, 6);
1948 if (rules[i].is_ipv6)
1949 memcpy (&r->src_ip_addr.ip6, rules[i].src_ip_addr, 16);
1951 memcpy (&r->src_ip_addr.ip4, rules[i].src_ip_addr, 4);
1952 r->src_prefixlen = rules[i].src_ip_prefix_len;
1955 if (~0 == *acl_list_index)
1958 pool_get_aligned (am->macip_acls, a, CLIB_CACHE_LINE_BYTES);
1959 memset (a, 0, sizeof (*a));
1960 /* Will return the newly allocated ACL index */
1961 *acl_list_index = a - am->macip_acls;
1965 a = pool_elt_at_index (am->macip_acls, *acl_list_index);
1968 vec_free (a->rules);
1970 macip_destroy_classify_tables (am, *acl_list_index);
1973 a->rules = acl_new_rules;
1975 memcpy (a->tag, tag, sizeof (a->tag));
1977 /* Create and populate the classifer tables */
1978 macip_create_classify_tables (am, *acl_list_index);
1979 clib_mem_set_heap (oldheap);
1980 /* If the ACL was already applied somewhere, reapply the newly created tables */
1982 || macip_maybe_apply_unapply_classifier_tables (am, *acl_list_index, 1);
1987 /* No check for validity of sw_if_index - the callers were supposed to validate */
1990 macip_acl_interface_del_acl (acl_main_t * am, u32 sw_if_index)
1993 u32 macip_acl_index;
1994 macip_acl_list_t *a;
1995 void *oldheap = acl_set_heap (am);
1996 vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
1997 clib_mem_set_heap (oldheap);
1998 macip_acl_index = am->macip_acl_by_sw_if_index[sw_if_index];
1999 /* No point in deleting MACIP ACL which is not applied */
2000 if (~0 == macip_acl_index)
2001 return VNET_API_ERROR_NO_SUCH_ENTRY;
2002 a = pool_elt_at_index (am->macip_acls, macip_acl_index);
2003 /* remove the classifier tables off the interface L2 ACL */
2005 vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
2006 a->ip6_table_index, a->l2_table_index, 0);
2008 vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
2009 a->out_ip4_table_index, a->out_ip6_table_index,
2010 a->out_l2_table_index, 0);
2011 /* Unset the MACIP ACL index */
2012 am->macip_acl_by_sw_if_index[sw_if_index] = ~0;
2016 /* No check for validity of sw_if_index - the callers were supposed to validate */
2019 macip_acl_interface_add_acl (acl_main_t * am, u32 sw_if_index,
2020 u32 macip_acl_index)
2022 macip_acl_list_t *a;
2024 if (pool_is_free_index (am->macip_acls, macip_acl_index))
2026 return VNET_API_ERROR_NO_SUCH_ENTRY;
2028 void *oldheap = acl_set_heap (am);
2029 a = pool_elt_at_index (am->macip_acls, macip_acl_index);
2030 vec_validate_init_empty (am->macip_acl_by_sw_if_index, sw_if_index, ~0);
2031 clib_mem_set_heap (oldheap);
2032 /* If there already a MACIP ACL applied, unapply it */
2033 if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2034 macip_acl_interface_del_acl (am, sw_if_index);
2035 am->macip_acl_by_sw_if_index[sw_if_index] = macip_acl_index;
2037 /* Apply the classifier tables for L2 ACLs */
2039 vnet_set_input_acl_intfc (am->vlib_main, sw_if_index, a->ip4_table_index,
2040 a->ip6_table_index, a->l2_table_index, 1);
2042 vnet_set_output_acl_intfc (am->vlib_main, sw_if_index,
2043 a->out_ip4_table_index, a->out_ip6_table_index,
2044 a->out_l2_table_index, 1);
2049 macip_acl_del_list (u32 acl_list_index)
2051 acl_main_t *am = &acl_main;
2052 macip_acl_list_t *a;
2054 if (pool_is_free_index (am->macip_acls, acl_list_index))
2056 return VNET_API_ERROR_NO_SUCH_ENTRY;
2059 /* delete any references to the ACL */
2060 for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
2062 if (am->macip_acl_by_sw_if_index[i] == acl_list_index)
2064 macip_acl_interface_del_acl (am, i);
2068 void *oldheap = acl_set_heap (am);
2069 /* Now that classifier tables are detached, clean them up */
2070 macip_destroy_classify_tables (am, acl_list_index);
2072 /* now we can delete the ACL itself */
2073 a = pool_elt_at_index (am->macip_acls, acl_list_index);
2076 vec_free (a->rules);
2078 pool_put (am->macip_acls, a);
2079 clib_mem_set_heap (oldheap);
2085 macip_acl_interface_add_del_acl (u32 sw_if_index, u8 is_add,
2088 acl_main_t *am = &acl_main;
2092 rv = macip_acl_interface_add_acl (am, sw_if_index, acl_list_index);
2096 rv = macip_acl_interface_del_acl (am, sw_if_index);
2102 * If the client does not allocate enough memory for a variable-length
2103 * message, and then proceed to use it as if the full memory allocated,
2104 * absent the check we happily consume that on the VPP side, and go
2105 * along as if nothing happened. However, the resulting
2106 * effects range from just garbage in the API decode
2107 * (because the decoder snoops too far), to potential memory
2110 * This verifies that the actual length of the message is
2111 * at least expected_len, and complains loudly if it is not.
2113 * A failing check here is 100% a software bug on the API user side,
2114 * so we might as well yell.
2118 verify_message_len (void *mp, u32 expected_len, char *where)
2120 u32 supplied_len = vl_msg_api_get_msg_length (mp);
2121 if (supplied_len < expected_len)
2123 clib_warning ("%s: Supplied message length %d is less than expected %d",
2124 where, supplied_len, expected_len);
2133 /* API message handler */
2135 vl_api_acl_add_replace_t_handler (vl_api_acl_add_replace_t * mp)
2137 vl_api_acl_add_replace_reply_t *rmp;
2138 acl_main_t *am = &acl_main;
2140 u32 acl_list_index = ntohl (mp->acl_index);
2141 u32 acl_count = ntohl (mp->count);
2142 u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2144 if (verify_message_len (mp, expected_len, "acl_add_replace"))
2146 rv = acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2150 rv = VNET_API_ERROR_INVALID_VALUE;
2154 REPLY_MACRO2(VL_API_ACL_ADD_REPLACE_REPLY,
2156 rmp->acl_index = htonl(acl_list_index);
2162 vl_api_acl_del_t_handler (vl_api_acl_del_t * mp)
2164 acl_main_t *am = &acl_main;
2165 vl_api_acl_del_reply_t *rmp;
2168 rv = acl_del_list (ntohl (mp->acl_index));
2170 REPLY_MACRO (VL_API_ACL_DEL_REPLY);
2174 vl_api_acl_interface_add_del_t_handler (vl_api_acl_interface_add_del_t * mp)
2176 acl_main_t *am = &acl_main;
2177 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2178 u32 sw_if_index = ntohl (mp->sw_if_index);
2179 vl_api_acl_interface_add_del_reply_t *rmp;
2182 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2183 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2186 acl_interface_add_del_inout_acl (sw_if_index, mp->is_add,
2187 mp->is_input, ntohl (mp->acl_index));
2189 REPLY_MACRO (VL_API_ACL_INTERFACE_ADD_DEL_REPLY);
2193 vl_api_acl_interface_set_acl_list_t_handler
2194 (vl_api_acl_interface_set_acl_list_t * mp)
2196 acl_main_t *am = &acl_main;
2197 vl_api_acl_interface_set_acl_list_reply_t *rmp;
2200 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2201 u32 sw_if_index = ntohl (mp->sw_if_index);
2203 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2204 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2207 acl_interface_reset_inout_acls (sw_if_index, 0);
2208 acl_interface_reset_inout_acls (sw_if_index, 1);
2210 for (i = 0; i < mp->count; i++)
2212 if (acl_is_not_defined (am, ntohl (mp->acls[i])))
2214 /* ACL does not exist, so we can not apply it */
2215 rv = VNET_API_ERROR_NO_SUCH_ENTRY;
2220 for (i = 0; i < mp->count; i++)
2222 acl_interface_add_del_inout_acl (sw_if_index, 1,
2224 ntohl (mp->acls[i]));
2229 REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ACL_LIST_REPLY);
2233 copy_acl_rule_to_api_rule (vl_api_acl_rule_t * api_rule, acl_rule_t * r)
2235 api_rule->is_permit = r->is_permit;
2236 api_rule->is_ipv6 = r->is_ipv6;
2239 memcpy (api_rule->src_ip_addr, &r->src, sizeof (r->src));
2240 memcpy (api_rule->dst_ip_addr, &r->dst, sizeof (r->dst));
2244 memcpy (api_rule->src_ip_addr, &r->src.ip4, sizeof (r->src.ip4));
2245 memcpy (api_rule->dst_ip_addr, &r->dst.ip4, sizeof (r->dst.ip4));
2247 api_rule->src_ip_prefix_len = r->src_prefixlen;
2248 api_rule->dst_ip_prefix_len = r->dst_prefixlen;
2249 api_rule->proto = r->proto;
2250 api_rule->srcport_or_icmptype_first = htons (r->src_port_or_type_first);
2251 api_rule->srcport_or_icmptype_last = htons (r->src_port_or_type_last);
2252 api_rule->dstport_or_icmpcode_first = htons (r->dst_port_or_code_first);
2253 api_rule->dstport_or_icmpcode_last = htons (r->dst_port_or_code_last);
2254 api_rule->tcp_flags_mask = r->tcp_flags_mask;
2255 api_rule->tcp_flags_value = r->tcp_flags_value;
2259 send_acl_details (acl_main_t * am, vl_api_registration_t * reg,
2260 acl_list_t * acl, u32 context)
2262 vl_api_acl_details_t *mp;
2263 vl_api_acl_rule_t *rules;
2265 int msg_size = sizeof (*mp) + sizeof (mp->r[0]) * acl->count;
2266 void *oldheap = acl_set_heap (am);
2268 mp = vl_msg_api_alloc (msg_size);
2269 memset (mp, 0, msg_size);
2270 mp->_vl_msg_id = ntohs (VL_API_ACL_DETAILS + am->msg_id_base);
2272 /* fill in the message */
2273 mp->context = context;
2274 mp->count = htonl (acl->count);
2275 mp->acl_index = htonl (acl - am->acls);
2276 memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2277 // clib_memcpy (mp->r, acl->rules, acl->count * sizeof(acl->rules[0]));
2279 for (i = 0; i < acl->count; i++)
2281 copy_acl_rule_to_api_rule (&rules[i], &acl->rules[i]);
2284 clib_mem_set_heap (oldheap);
2285 vl_api_send_msg (reg, (u8 *) mp);
2290 vl_api_acl_dump_t_handler (vl_api_acl_dump_t * mp)
2292 acl_main_t *am = &acl_main;
2296 vl_api_registration_t *reg;
2298 reg = vl_api_client_index_to_registration (mp->client_index);
2302 if (mp->acl_index == ~0)
2305 /* Just dump all ACLs */
2306 pool_foreach (acl, am->acls,
2308 send_acl_details(am, reg, acl, mp->context);
2314 acl_index = ntohl (mp->acl_index);
2315 if (!pool_is_free_index (am->acls, acl_index))
2317 acl = pool_elt_at_index (am->acls, acl_index);
2318 send_acl_details (am, reg, acl, mp->context);
2324 /* FIXME API: should we signal an error here at all ? */
2330 send_acl_interface_list_details (acl_main_t * am,
2331 vl_api_registration_t * reg,
2332 u32 sw_if_index, u32 context)
2334 vl_api_acl_interface_list_details_t *mp;
2340 void *oldheap = acl_set_heap (am);
2342 vec_validate (am->input_acl_vec_by_sw_if_index, sw_if_index);
2343 vec_validate (am->output_acl_vec_by_sw_if_index, sw_if_index);
2345 n_input = vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]);
2346 n_output = vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]);
2347 count = n_input + n_output;
2349 msg_size = sizeof (*mp);
2350 msg_size += sizeof (mp->acls[0]) * count;
2352 mp = vl_msg_api_alloc (msg_size);
2353 memset (mp, 0, msg_size);
2355 ntohs (VL_API_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2357 /* fill in the message */
2358 mp->context = context;
2359 mp->sw_if_index = htonl (sw_if_index);
2361 mp->n_input = n_input;
2362 for (i = 0; i < n_input; i++)
2364 mp->acls[i] = htonl (am->input_acl_vec_by_sw_if_index[sw_if_index][i]);
2366 for (i = 0; i < n_output; i++)
2368 mp->acls[n_input + i] =
2369 htonl (am->output_acl_vec_by_sw_if_index[sw_if_index][i]);
2371 clib_mem_set_heap (oldheap);
2372 vl_api_send_msg (reg, (u8 *) mp);
2376 vl_api_acl_interface_list_dump_t_handler (vl_api_acl_interface_list_dump_t *
2379 acl_main_t *am = &acl_main;
2380 vnet_sw_interface_t *swif;
2381 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2384 vl_api_registration_t *reg;
2386 reg = vl_api_client_index_to_registration (mp->client_index);
2390 if (mp->sw_if_index == ~0)
2393 pool_foreach (swif, im->sw_interfaces,
2395 send_acl_interface_list_details(am, reg, swif->sw_if_index, mp->context);
2401 sw_if_index = ntohl (mp->sw_if_index);
2402 if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2403 send_acl_interface_list_details (am, reg, sw_if_index, mp->context);
2407 /* MACIP ACL API handlers */
2410 vl_api_macip_acl_add_t_handler (vl_api_macip_acl_add_t * mp)
2412 vl_api_macip_acl_add_reply_t *rmp;
2413 acl_main_t *am = &acl_main;
2415 u32 acl_list_index = ~0;
2416 u32 acl_count = ntohl (mp->count);
2417 u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2419 if (verify_message_len (mp, expected_len, "macip_acl_add"))
2421 rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2425 rv = VNET_API_ERROR_INVALID_VALUE;
2429 REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLY,
2431 rmp->acl_index = htonl(acl_list_index);
2437 vl_api_macip_acl_add_replace_t_handler (vl_api_macip_acl_add_replace_t * mp)
2439 vl_api_macip_acl_add_replace_reply_t *rmp;
2440 acl_main_t *am = &acl_main;
2442 u32 acl_list_index = ntohl (mp->acl_index);
2443 u32 acl_count = ntohl (mp->count);
2444 u32 expected_len = sizeof (*mp) + acl_count * sizeof (mp->r[0]);
2446 if (verify_message_len (mp, expected_len, "macip_acl_add_replace"))
2448 rv = macip_acl_add_list (acl_count, mp->r, &acl_list_index, mp->tag);
2452 rv = VNET_API_ERROR_INVALID_VALUE;
2456 REPLY_MACRO2(VL_API_MACIP_ACL_ADD_REPLACE_REPLY,
2458 rmp->acl_index = htonl(acl_list_index);
2464 vl_api_macip_acl_del_t_handler (vl_api_macip_acl_del_t * mp)
2466 acl_main_t *am = &acl_main;
2467 vl_api_macip_acl_del_reply_t *rmp;
2470 rv = macip_acl_del_list (ntohl (mp->acl_index));
2472 REPLY_MACRO (VL_API_MACIP_ACL_DEL_REPLY);
2476 vl_api_macip_acl_interface_add_del_t_handler
2477 (vl_api_macip_acl_interface_add_del_t * mp)
2479 acl_main_t *am = &acl_main;
2480 vl_api_macip_acl_interface_add_del_reply_t *rmp;
2482 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2483 u32 sw_if_index = ntohl (mp->sw_if_index);
2485 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2486 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2489 macip_acl_interface_add_del_acl (ntohl (mp->sw_if_index), mp->is_add,
2490 ntohl (mp->acl_index));
2492 REPLY_MACRO (VL_API_MACIP_ACL_INTERFACE_ADD_DEL_REPLY);
2496 send_macip_acl_details (acl_main_t * am, vl_api_registration_t * reg,
2497 macip_acl_list_t * acl, u32 context)
2499 vl_api_macip_acl_details_t *mp;
2500 vl_api_macip_acl_rule_t *rules;
2501 macip_acl_rule_t *r;
2503 int msg_size = sizeof (*mp) + (acl ? sizeof (mp->r[0]) * acl->count : 0);
2505 mp = vl_msg_api_alloc (msg_size);
2506 memset (mp, 0, msg_size);
2507 mp->_vl_msg_id = ntohs (VL_API_MACIP_ACL_DETAILS + am->msg_id_base);
2509 /* fill in the message */
2510 mp->context = context;
2513 memcpy (mp->tag, acl->tag, sizeof (mp->tag));
2514 mp->count = htonl (acl->count);
2515 mp->acl_index = htonl (acl - am->macip_acls);
2517 for (i = 0; i < acl->count; i++)
2520 rules[i].is_permit = r->is_permit;
2521 rules[i].is_ipv6 = r->is_ipv6;
2522 memcpy (rules[i].src_mac, &r->src_mac, sizeof (r->src_mac));
2523 memcpy (rules[i].src_mac_mask, &r->src_mac_mask,
2524 sizeof (r->src_mac_mask));
2526 memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip6,
2527 sizeof (r->src_ip_addr.ip6));
2529 memcpy (rules[i].src_ip_addr, &r->src_ip_addr.ip4,
2530 sizeof (r->src_ip_addr.ip4));
2531 rules[i].src_ip_prefix_len = r->src_prefixlen;
2536 /* No martini, no party - no ACL applied to this interface. */
2541 vl_api_send_msg (reg, (u8 *) mp);
2546 vl_api_macip_acl_dump_t_handler (vl_api_macip_acl_dump_t * mp)
2548 acl_main_t *am = &acl_main;
2549 macip_acl_list_t *acl;
2551 vl_api_registration_t *reg;
2553 reg = vl_api_client_index_to_registration (mp->client_index);
2557 if (mp->acl_index == ~0)
2559 /* Just dump all ACLs for now, with sw_if_index = ~0 */
2560 pool_foreach (acl, am->macip_acls, (
2562 send_macip_acl_details (am, reg,
2571 u32 acl_index = ntohl (mp->acl_index);
2572 if (!pool_is_free_index (am->macip_acls, acl_index))
2574 acl = pool_elt_at_index (am->macip_acls, acl_index);
2575 send_macip_acl_details (am, reg, acl, mp->context);
2581 vl_api_macip_acl_interface_get_t_handler (vl_api_macip_acl_interface_get_t *
2584 acl_main_t *am = &acl_main;
2585 vl_api_macip_acl_interface_get_reply_t *rmp;
2586 u32 count = vec_len (am->macip_acl_by_sw_if_index);
2587 int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]) * count;
2588 vl_api_registration_t *reg;
2591 reg = vl_api_client_index_to_registration (mp->client_index);
2595 rmp = vl_msg_api_alloc (msg_size);
2596 memset (rmp, 0, msg_size);
2598 ntohs (VL_API_MACIP_ACL_INTERFACE_GET_REPLY + am->msg_id_base);
2599 rmp->context = mp->context;
2600 rmp->count = htonl (count);
2601 for (i = 0; i < count; i++)
2603 rmp->acls[i] = htonl (am->macip_acl_by_sw_if_index[i]);
2606 vl_api_send_msg (reg, (u8 *) rmp);
2610 send_macip_acl_interface_list_details (acl_main_t * am,
2611 vl_api_registration_t * reg,
2613 u32 acl_index, u32 context)
2615 vl_api_macip_acl_interface_list_details_t *rmp;
2616 /* at this time there is only ever 1 mac ip acl per interface */
2617 int msg_size = sizeof (*rmp) + sizeof (rmp->acls[0]);
2619 rmp = vl_msg_api_alloc (msg_size);
2620 memset (rmp, 0, msg_size);
2622 ntohs (VL_API_MACIP_ACL_INTERFACE_LIST_DETAILS + am->msg_id_base);
2624 /* fill in the message */
2625 rmp->context = context;
2627 rmp->sw_if_index = htonl (sw_if_index);
2628 rmp->acls[0] = htonl (acl_index);
2630 vl_api_send_msg (reg, (u8 *) rmp);
2634 vl_api_macip_acl_interface_list_dump_t_handler
2635 (vl_api_macip_acl_interface_list_dump_t * mp)
2637 vl_api_registration_t *reg;
2638 acl_main_t *am = &acl_main;
2639 u32 sw_if_index = ntohl (mp->sw_if_index);
2641 reg = vl_api_client_index_to_registration (mp->client_index);
2645 if (sw_if_index == ~0)
2647 vec_foreach_index (sw_if_index, am->macip_acl_by_sw_if_index)
2649 if (~0 != am->macip_acl_by_sw_if_index[sw_if_index])
2651 send_macip_acl_interface_list_details (am, reg, sw_if_index,
2652 am->macip_acl_by_sw_if_index
2660 if (vec_len (am->macip_acl_by_sw_if_index) > sw_if_index)
2662 send_macip_acl_interface_list_details (am, reg, sw_if_index,
2663 am->macip_acl_by_sw_if_index
2664 [sw_if_index], mp->context);
2670 vl_api_acl_interface_set_etype_whitelist_t_handler
2671 (vl_api_acl_interface_set_etype_whitelist_t * mp)
2673 acl_main_t *am = &acl_main;
2674 vl_api_acl_interface_set_etype_whitelist_reply_t *rmp;
2677 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2678 u32 sw_if_index = ntohl (mp->sw_if_index);
2679 u16 *vec_in = 0, *vec_out = 0;
2680 void *oldheap = acl_set_heap (am);
2682 if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2683 rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
2686 for (i = 0; i < mp->count; i++)
2688 if (i < mp->n_input)
2689 vec_add1 (vec_in, ntohs (mp->whitelist[i]));
2691 vec_add1 (vec_out, ntohs (mp->whitelist[i]));
2693 rv = acl_set_etype_whitelists (am, sw_if_index, vec_in, vec_out);
2696 clib_mem_set_heap (oldheap);
2697 REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY);
2701 send_acl_interface_etype_whitelist_details (acl_main_t * am,
2702 vl_api_registration_t * reg,
2703 u32 sw_if_index, u32 context)
2705 vl_api_acl_interface_etype_whitelist_details_t *mp;
2712 u16 *whitelist_in = 0;
2713 u16 *whitelist_out = 0;
2715 if (intf_has_etype_whitelist (am, sw_if_index, 0))
2717 vec_elt (am->output_etype_whitelist_by_sw_if_index, sw_if_index);
2719 if (intf_has_etype_whitelist (am, sw_if_index, 1))
2721 vec_elt (am->input_etype_whitelist_by_sw_if_index, sw_if_index);
2723 if ((0 == whitelist_in) && (0 == whitelist_out))
2724 return; /* nothing to do */
2726 void *oldheap = acl_set_heap (am);
2728 n_input = vec_len (whitelist_in);
2729 n_output = vec_len (whitelist_out);
2730 count = n_input + n_output;
2732 msg_size = sizeof (*mp);
2733 msg_size += sizeof (mp->whitelist[0]) * count;
2735 mp = vl_msg_api_alloc (msg_size);
2736 memset (mp, 0, msg_size);
2738 ntohs (VL_API_ACL_INTERFACE_ETYPE_WHITELIST_DETAILS + am->msg_id_base);
2740 /* fill in the message */
2741 mp->context = context;
2742 mp->sw_if_index = htonl (sw_if_index);
2744 mp->n_input = n_input;
2745 for (i = 0; i < n_input; i++)
2747 mp->whitelist[i] = htons (whitelist_in[i]);
2749 for (i = 0; i < n_output; i++)
2751 mp->whitelist[n_input + i] = htons (whitelist_out[i]);
2753 clib_mem_set_heap (oldheap);
2754 vl_api_send_msg (reg, (u8 *) mp);
2759 vl_api_acl_interface_etype_whitelist_dump_t_handler
2760 (vl_api_acl_interface_list_dump_t * mp)
2762 acl_main_t *am = &acl_main;
2763 vnet_sw_interface_t *swif;
2764 vnet_interface_main_t *im = &am->vnet_main->interface_main;
2767 vl_api_registration_t *reg;
2769 reg = vl_api_client_index_to_registration (mp->client_index);
2773 if (mp->sw_if_index == ~0)
2776 pool_foreach (swif, im->sw_interfaces,
2778 send_acl_interface_etype_whitelist_details(am, reg, swif->sw_if_index, mp->context);
2784 sw_if_index = ntohl (mp->sw_if_index);
2785 if (!pool_is_free_index (im->sw_interfaces, sw_if_index))
2786 send_acl_interface_etype_whitelist_details (am, reg, sw_if_index,
2793 /* Set up the API message handling tables */
2794 static clib_error_t *
2795 acl_plugin_api_hookup (vlib_main_t * vm)
2797 acl_main_t *am = &acl_main;
2799 vl_msg_api_set_handlers((VL_API_##N + am->msg_id_base), \
2801 vl_api_##n##_t_handler, \
2803 vl_api_##n##_t_endian, \
2804 vl_api_##n##_t_print, \
2805 sizeof(vl_api_##n##_t), 1);
2806 foreach_acl_plugin_api_msg;
2812 #define vl_msg_name_crc_list
2813 #include <acl/acl_all_api_h.h>
2814 #undef vl_msg_name_crc_list
2817 setup_message_id_table (acl_main_t * am, api_main_t * apim)
2819 #define _(id,n,crc) \
2820 vl_msg_api_add_msg_name_crc (apim, #n "_" #crc, id + am->msg_id_base);
2821 foreach_vl_msg_name_crc_acl;
2826 acl_setup_fa_nodes (void)
2828 vlib_main_t *vm = vlib_get_main ();
2829 acl_main_t *am = &acl_main;
2830 vlib_node_t *n, *n4, *n6;
2832 n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify");
2833 n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2");
2834 n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2");
2837 am->l2_input_classify_next_acl_ip4 =
2838 vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
2839 am->l2_input_classify_next_acl_ip6 =
2840 vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
2842 feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT,
2843 l2input_get_feat_names (),
2844 am->fa_acl_in_ip4_l2_node_feat_next_node_index);
2846 feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT,
2847 l2input_get_feat_names (),
2848 am->fa_acl_in_ip6_l2_node_feat_next_node_index);
2851 n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify");
2852 n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2");
2853 n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2");
2855 am->l2_output_classify_next_acl_ip4 =
2856 vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0);
2857 am->l2_output_classify_next_acl_ip6 =
2858 vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0);
2860 feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT,
2861 l2output_get_feat_names (),
2862 am->fa_acl_out_ip4_l2_node_feat_next_node_index);
2864 feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT,
2865 l2output_get_feat_names (),
2866 am->fa_acl_out_ip6_l2_node_feat_next_node_index);
2870 acl_set_timeout_sec (int timeout_type, u32 value)
2872 acl_main_t *am = &acl_main;
2873 clib_time_t *ct = &am->vlib_main->clib_time;
2875 if (timeout_type < ACL_N_TIMEOUTS)
2877 am->session_timeout_sec[timeout_type] = value;
2881 clib_warning ("Unknown timeout type %d", timeout_type);
2884 am->session_timeout[timeout_type] =
2885 (u64) (((f64) value) / ct->seconds_per_clock);
2889 acl_set_session_max_entries (u32 value)
2891 acl_main_t *am = &acl_main;
2892 am->fa_conn_table_max_entries = value;
2896 acl_set_skip_ipv6_eh (u32 eh, u32 value)
2898 acl_main_t *am = &acl_main;
2900 if ((eh < 256) && (value < 2))
2902 am->fa_ipv6_known_eh_bitmap =
2903 clib_bitmap_set (am->fa_ipv6_known_eh_bitmap, eh, value);
2911 static clib_error_t *
2912 acl_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
2914 acl_main_t *am = &acl_main;
2915 if (0 == am->acl_mheap)
2917 /* ACL heap is not initialized, so definitely nothing to do. */
2922 vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
2923 ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX,
2925 /* also unapply any ACLs in case the users did not do so. */
2926 macip_acl_interface_del_acl (am, sw_if_index);
2927 acl_interface_reset_inout_acls (sw_if_index, 0);
2928 acl_interface_reset_inout_acls (sw_if_index, 1);
2933 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (acl_sw_interface_add_del);
2937 static clib_error_t *
2938 acl_set_aclplugin_fn (vlib_main_t * vm,
2939 unformat_input_t * input, vlib_cli_command_t * cmd)
2941 clib_error_t *error = 0;
2945 uword memory_size = 0;
2946 acl_main_t *am = &acl_main;
2948 if (unformat (input, "skip-ipv6-extension-header %u %u", &eh_val, &val))
2950 if (!acl_set_skip_ipv6_eh (eh_val, val))
2952 error = clib_error_return (0, "expecting eh=0..255, value=0..1");
2956 if (unformat (input, "use-hash-acl-matching %u", &val))
2958 am->use_hash_acl_matching = (val != 0);
2961 if (unformat (input, "l4-match-nonfirst-fragment %u", &val))
2963 am->l4_match_nonfirst_fragment = (val != 0);
2966 if (unformat (input, "heap"))
2968 if (unformat (input, "main"))
2970 if (unformat (input, "validate %u", &val))
2971 acl_plugin_acl_set_validate_heap (am, val);
2972 else if (unformat (input, "trace %u", &val))
2973 acl_plugin_acl_set_trace_heap (am, val);
2976 else if (unformat (input, "hash"))
2978 if (unformat (input, "validate %u", &val))
2979 acl_plugin_hash_acl_set_validate_heap (am, val);
2980 else if (unformat (input, "trace %u", &val))
2981 acl_plugin_hash_acl_set_trace_heap (am, val);
2986 if (unformat (input, "session"))
2988 if (unformat (input, "table"))
2990 /* The commands here are for tuning/testing. No user-serviceable parts inside */
2991 if (unformat (input, "max-entries"))
2993 if (!unformat (input, "%u", &val))
2995 error = clib_error_return (0,
2996 "expecting maximum number of entries, got `%U`",
2997 format_unformat_error, input);
3002 acl_set_session_max_entries (val);
3006 if (unformat (input, "hash-table-buckets"))
3008 if (!unformat (input, "%u", &val))
3010 error = clib_error_return (0,
3011 "expecting maximum number of hash table buckets, got `%U`",
3012 format_unformat_error, input);
3017 am->fa_conn_table_hash_num_buckets = val;
3021 if (unformat (input, "hash-table-memory"))
3023 if (!unformat (input, "%U", unformat_memory_size, &memory_size))
3025 error = clib_error_return (0,
3026 "expecting maximum amount of hash table memory, got `%U`",
3027 format_unformat_error, input);
3032 am->fa_conn_table_hash_memory_size = memory_size;
3036 if (unformat (input, "event-trace"))
3038 if (!unformat (input, "%u", &val))
3040 error = clib_error_return (0,
3041 "expecting trace level, got `%U`",
3042 format_unformat_error, input);
3047 am->trace_sessions = val;
3053 if (unformat (input, "timeout"))
3055 if (unformat (input, "udp"))
3057 if (unformat (input, "idle"))
3059 if (!unformat (input, "%u", &timeout))
3061 error = clib_error_return (0,
3062 "expecting timeout value in seconds, got `%U`",
3063 format_unformat_error,
3069 acl_set_timeout_sec (ACL_TIMEOUT_UDP_IDLE, timeout);
3074 if (unformat (input, "tcp"))
3076 if (unformat (input, "idle"))
3078 if (!unformat (input, "%u", &timeout))
3080 error = clib_error_return (0,
3081 "expecting timeout value in seconds, got `%U`",
3082 format_unformat_error,
3088 acl_set_timeout_sec (ACL_TIMEOUT_TCP_IDLE, timeout);
3092 if (unformat (input, "transient"))
3094 if (!unformat (input, "%u", &timeout))
3096 error = clib_error_return (0,
3097 "expecting timeout value in seconds, got `%U`",
3098 format_unformat_error,
3104 acl_set_timeout_sec (ACL_TIMEOUT_TCP_TRANSIENT,
3118 my_format_mac_address (u8 * s, va_list * args)
3120 u8 *a = va_arg (*args, u8 *);
3121 return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
3122 a[0], a[1], a[2], a[3], a[4], a[5]);
3126 my_macip_acl_rule_t_pretty_format (u8 * out, va_list * args)
3128 macip_acl_rule_t *a = va_arg (*args, macip_acl_rule_t *);
3130 out = format (out, "%s action %d ip %U/%d mac %U mask %U",
3131 a->is_ipv6 ? "ipv6" : "ipv4", a->is_permit,
3132 format_ip46_address, &a->src_ip_addr,
3133 a->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
3135 my_format_mac_address, a->src_mac,
3136 my_format_mac_address, a->src_mac_mask);
3141 macip_acl_print (acl_main_t * am, u32 macip_acl_index)
3143 vlib_main_t *vm = am->vlib_main;
3146 /* Don't attempt to show the ACLs that do not exist */
3147 if (pool_is_free_index (am->macip_acls, macip_acl_index))
3150 /* Don't try to print someone else's memory */
3151 if (macip_acl_index > vec_len (am->macip_acls))
3154 macip_acl_list_t *a = vec_elt_at_index (am->macip_acls, macip_acl_index);
3155 int free_pool_slot = pool_is_free_index (am->macip_acls, macip_acl_index);
3157 vlib_cli_output (vm,
3158 "MACIP acl_index: %d, count: %d (true len %d) tag {%s} is free pool slot: %d\n",
3159 macip_acl_index, a->count, vec_len (a->rules), a->tag,
3161 vlib_cli_output (vm,
3162 " ip4_table_index %d, ip6_table_index %d, l2_table_index %d\n",
3163 a->ip4_table_index, a->ip6_table_index, a->l2_table_index);
3164 vlib_cli_output (vm,
3165 " out_ip4_table_index %d, out_ip6_table_index %d, out_l2_table_index %d\n",
3166 a->out_ip4_table_index, a->out_ip6_table_index,
3167 a->out_l2_table_index);
3168 for (i = 0; i < vec_len (a->rules); i++)
3169 vlib_cli_output (vm, " rule %d: %U\n", i,
3170 my_macip_acl_rule_t_pretty_format,
3171 vec_elt_at_index (a->rules, i));
3175 static clib_error_t *
3176 acl_show_aclplugin_macip_acl_fn (vlib_main_t * vm,
3178 input, vlib_cli_command_t * cmd)
3180 clib_error_t *error = 0;
3181 acl_main_t *am = &acl_main;
3183 for (i = 0; i < vec_len (am->macip_acls); i++)
3184 macip_acl_print (am, i);
3188 static clib_error_t *
3189 acl_show_aclplugin_macip_interface_fn (vlib_main_t * vm,
3191 input, vlib_cli_command_t * cmd)
3193 clib_error_t *error = 0;
3194 acl_main_t *am = &acl_main;
3196 for (i = 0; i < vec_len (am->macip_acl_by_sw_if_index); i++)
3198 vlib_cli_output (vm, " sw_if_index %d: %d\n", i,
3199 vec_elt (am->macip_acl_by_sw_if_index, i));
3204 #define PRINT_AND_RESET(vm, out0) do { vlib_cli_output(vm, "%v", out0); vec_reset_length(out0); } while(0)
3206 acl_print_acl (vlib_main_t * vm, acl_main_t * am, int acl_index)
3209 u8 *out0 = format (0, "acl-index %u count %u tag {%s}\n", acl_index,
3210 am->acls[acl_index].count, am->acls[acl_index].tag);
3212 PRINT_AND_RESET (vm, out0);
3213 for (j = 0; j < am->acls[acl_index].count; j++)
3215 r = &am->acls[acl_index].rules[j];
3216 out0 = format (out0, " %4d: %s ", j, r->is_ipv6 ? "ipv6" : "ipv4");
3217 out0 = format_acl_action (out0, r->is_permit);
3218 out0 = format (out0, " src %U/%d", format_ip46_address, &r->src,
3219 r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4,
3222 format (out0, " dst %U/%d", format_ip46_address, &r->dst,
3223 r->is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, r->dst_prefixlen);
3224 out0 = format (out0, " proto %d", r->proto);
3225 out0 = format (out0, " sport %d", r->src_port_or_type_first);
3226 if (r->src_port_or_type_first != r->src_port_or_type_last)
3228 out0 = format (out0, "-%d", r->src_port_or_type_last);
3230 out0 = format (out0, " dport %d", r->dst_port_or_code_first);
3231 if (r->dst_port_or_code_first != r->dst_port_or_code_last)
3233 out0 = format (out0, "-%d", r->dst_port_or_code_last);
3235 if (r->tcp_flags_mask || r->tcp_flags_value)
3238 format (out0, " tcpflags %d mask %d", r->tcp_flags_value,
3241 out0 = format (out0, "\n");
3242 PRINT_AND_RESET (vm, out0);
3246 #undef PRINT_AND_RESET
3249 acl_plugin_show_acl (acl_main_t * am, u32 acl_index)
3252 vlib_main_t *vm = am->vlib_main;
3254 for (i = 0; i < vec_len (am->acls); i++)
3256 if (acl_is_not_defined (am, i))
3258 /* don't attempt to show the ACLs that do not exist */
3261 if ((acl_index != ~0) && (acl_index != i))
3265 acl_print_acl (vm, am, i);
3267 if (i < vec_len (am->input_sw_if_index_vec_by_acl))
3269 vlib_cli_output (vm, " applied inbound on sw_if_index: %U\n",
3270 format_vec32, am->input_sw_if_index_vec_by_acl[i],
3273 if (i < vec_len (am->output_sw_if_index_vec_by_acl))
3275 vlib_cli_output (vm, " applied outbound on sw_if_index: %U\n",
3276 format_vec32, am->output_sw_if_index_vec_by_acl[i],
3282 static clib_error_t *
3283 acl_show_aclplugin_acl_fn (vlib_main_t * vm,
3284 unformat_input_t * input, vlib_cli_command_t * cmd)
3286 clib_error_t *error = 0;
3287 acl_main_t *am = &acl_main;
3290 (void) unformat (input, "index %u", &acl_index);
3292 acl_plugin_show_acl (am, acl_index);
3297 acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl)
3299 vlib_main_t *vm = am->vlib_main;
3302 for (swi = 0; (swi < vec_len (am->input_acl_vec_by_sw_if_index)) ||
3303 (swi < vec_len (am->output_acl_vec_by_sw_if_index)); swi++)
3305 /* if we need a particular interface, skip all the others */
3306 if ((sw_if_index != ~0) && (sw_if_index != swi))
3309 vlib_cli_output (vm, "sw_if_index %d:\n", swi);
3311 if (intf_has_etype_whitelist (am, swi, 1))
3313 vlib_cli_output (vm, " input etype whitelist: %U", format_vec16,
3314 am->input_etype_whitelist_by_sw_if_index[swi],
3317 if (intf_has_etype_whitelist (am, swi, 0))
3319 vlib_cli_output (vm, " output etype whitelist: %U", format_vec16,
3320 am->output_etype_whitelist_by_sw_if_index[swi],
3324 if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) &&
3325 (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0))
3327 vlib_cli_output (vm, " input acl(s): %U", format_vec32,
3328 am->input_acl_vec_by_sw_if_index[swi], "%d");
3331 vlib_cli_output (vm, "\n");
3332 vec_foreach (pj, am->input_acl_vec_by_sw_if_index[swi])
3334 acl_print_acl (vm, am, *pj);
3336 vlib_cli_output (vm, "\n");
3340 if ((swi < vec_len (am->output_acl_vec_by_sw_if_index)) &&
3341 (vec_len (am->output_acl_vec_by_sw_if_index[swi]) > 0))
3343 vlib_cli_output (vm, " output acl(s): %U", format_vec32,
3344 am->output_acl_vec_by_sw_if_index[swi], "%d");
3347 vlib_cli_output (vm, "\n");
3348 vec_foreach (pj, am->output_acl_vec_by_sw_if_index[swi])
3350 acl_print_acl (vm, am, *pj);
3352 vlib_cli_output (vm, "\n");
3360 static clib_error_t *
3361 acl_show_aclplugin_decode_5tuple_fn (vlib_main_t * vm,
3362 unformat_input_t * input,
3363 vlib_cli_command_t * cmd)
3365 clib_error_t *error = 0;
3366 u64 five_tuple[6] = { 0, 0, 0, 0, 0, 0 };
3369 (input, "%llx %llx %llx %llx %llx %llx", &five_tuple[0], &five_tuple[1],
3370 &five_tuple[2], &five_tuple[3], &five_tuple[4], &five_tuple[5]))
3371 vlib_cli_output (vm, "5-tuple structure decode: %U\n\n",
3372 format_acl_plugin_5tuple, five_tuple);
3374 error = clib_error_return (0, "expecting 6 hex integers");
3379 static clib_error_t *
3380 acl_show_aclplugin_interface_fn (vlib_main_t * vm,
3382 input, vlib_cli_command_t * cmd)
3384 clib_error_t *error = 0;
3385 acl_main_t *am = &acl_main;
3387 u32 sw_if_index = ~0;
3388 (void) unformat (input, "sw_if_index %u", &sw_if_index);
3389 int show_acl = unformat (input, "acl");
3391 acl_plugin_show_interface (am, sw_if_index, show_acl);
3395 static clib_error_t *
3396 acl_show_aclplugin_memory_fn (vlib_main_t * vm,
3397 unformat_input_t * input,
3398 vlib_cli_command_t * cmd)
3400 clib_error_t *error = 0;
3401 acl_main_t *am = &acl_main;
3403 vlib_cli_output (vm, "ACL plugin main heap statistics:\n");
3406 vlib_cli_output (vm, " %U\n", format_mheap, am->acl_mheap, 1);
3410 vlib_cli_output (vm, " Not initialized\n");
3412 vlib_cli_output (vm, "ACL hash lookup support heap statistics:\n");
3413 if (am->hash_lookup_mheap)
3415 vlib_cli_output (vm, " %U\n", format_mheap, am->hash_lookup_mheap, 1);
3419 vlib_cli_output (vm, " Not initialized\n");
3425 acl_plugin_show_sessions (acl_main_t * am,
3426 u32 show_session_thread_id,
3427 u32 show_session_session_index)
3429 vlib_main_t *vm = am->vlib_main;
3431 vnet_interface_main_t *im = &am->vnet_main->interface_main;
3432 vnet_sw_interface_t *swif;
3435 u64 n_adds = am->fa_session_total_adds;
3436 u64 n_dels = am->fa_session_total_dels;
3437 vlib_cli_output (vm, "Sessions total: add %lu - del %lu = %lu", n_adds,
3438 n_dels, n_adds - n_dels);
3440 vlib_cli_output (vm, "\n\nPer-thread data:");
3441 for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3443 acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3444 vlib_cli_output (vm, "Thread #%d:", wk);
3445 if (show_session_thread_id == wk
3446 && show_session_session_index < pool_len (pw->fa_sessions_pool))
3448 vlib_cli_output (vm, " session index %u:",
3449 show_session_session_index);
3450 fa_session_t *sess =
3451 pw->fa_sessions_pool + show_session_session_index;
3452 u64 *m = (u64 *) & sess->info;
3453 vlib_cli_output (vm,
3454 " info: %016llx %016llx %016llx %016llx %016llx %016llx",
3455 m[0], m[1], m[2], m[3], m[4], m[5]);
3456 vlib_cli_output (vm, " sw_if_index: %u", sess->sw_if_index);
3457 vlib_cli_output (vm, " tcp_flags_seen: %x",
3458 sess->tcp_flags_seen.as_u16);
3459 vlib_cli_output (vm, " last active time: %lu",
3460 sess->last_active_time);
3461 vlib_cli_output (vm, " thread index: %u", sess->thread_index);
3462 vlib_cli_output (vm, " link enqueue time: %lu",
3463 sess->link_enqueue_time);
3464 vlib_cli_output (vm, " link next index: %u",
3465 sess->link_next_idx);
3466 vlib_cli_output (vm, " link prev index: %u",
3467 sess->link_prev_idx);
3468 vlib_cli_output (vm, " link list id: %u", sess->link_list_id);
3470 vlib_cli_output (vm, " connection add/del stats:", wk);
3471 pool_foreach (swif, im->sw_interfaces, (
3478 (pw->fa_session_adds_by_sw_if_index)
3480 pw->fa_session_adds_by_sw_if_index
3485 (pw->fa_session_dels_by_sw_if_index)
3487 pw->fa_session_dels_by_sw_if_index
3489 vlib_cli_output (vm,
3490 " sw_if_index %d: add %lu - del %lu = %lu",
3499 vlib_cli_output (vm, " connection timeout type lists:", wk);
3501 for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
3503 u32 head_session_index = pw->fa_conn_list_head[tt];
3504 vlib_cli_output (vm, " fa_conn_list_head[%d]: %d", tt,
3505 head_session_index);
3506 if (~0 != head_session_index)
3508 fa_session_t *sess = pw->fa_sessions_pool + head_session_index;
3509 vlib_cli_output (vm, " last active time: %lu",
3510 sess->last_active_time);
3511 vlib_cli_output (vm, " link enqueue time: %lu",
3512 sess->link_enqueue_time);
3516 vlib_cli_output (vm, " Next expiry time: %lu", pw->next_expiry_time);
3517 vlib_cli_output (vm, " Requeue until time: %lu",
3518 pw->requeue_until_time);
3519 vlib_cli_output (vm, " Current time wait interval: %lu",
3520 pw->current_time_wait_interval);
3521 vlib_cli_output (vm, " Count of deleted sessions: %lu",
3522 pw->cnt_deleted_sessions);
3523 vlib_cli_output (vm, " Delete already deleted: %lu",
3524 pw->cnt_already_deleted_sessions);
3525 vlib_cli_output (vm, " Session timers restarted: %lu",
3526 pw->cnt_session_timer_restarted);
3527 vlib_cli_output (vm, " Swipe until this time: %lu",
3528 pw->swipe_end_time);
3529 vlib_cli_output (vm, " sw_if_index serviced bitmap: %U",
3530 format_bitmap_hex, pw->serviced_sw_if_index_bitmap);
3531 vlib_cli_output (vm, " pending clear intfc bitmap : %U",
3533 pw->pending_clear_sw_if_index_bitmap);
3534 vlib_cli_output (vm, " clear in progress: %u", pw->clear_in_process);
3535 vlib_cli_output (vm, " interrupt is pending: %d",
3536 pw->interrupt_is_pending);
3537 vlib_cli_output (vm, " interrupt is needed: %d",
3538 pw->interrupt_is_needed);
3539 vlib_cli_output (vm, " interrupt is unwanted: %d",
3540 pw->interrupt_is_unwanted);
3541 vlib_cli_output (vm, " interrupt generation: %d",
3542 pw->interrupt_generation);
3544 vlib_cli_output (vm, "\n\nConn cleaner thread counters:");
3545 #define _(cnt, desc) vlib_cli_output(vm, " %20lu: %s", am->cnt, desc);
3546 foreach_fa_cleaner_counter;
3548 vlib_cli_output (vm, "Interrupt generation: %d",
3549 am->fa_interrupt_generation);
3550 vlib_cli_output (vm,
3551 "Sessions per interval: min %lu max %lu increment: %f ms current: %f ms",
3552 am->fa_min_deleted_sessions_per_interval,
3553 am->fa_max_deleted_sessions_per_interval,
3554 am->fa_cleaner_wait_time_increment * 1000.0,
3555 ((f64) am->fa_current_cleaner_timer_wait_interval) *
3556 1000.0 / (f64) vm->clib_time.clocks_per_second);
3559 static clib_error_t *
3560 acl_show_aclplugin_sessions_fn (vlib_main_t * vm,
3561 unformat_input_t * input,
3562 vlib_cli_command_t * cmd)
3564 clib_error_t *error = 0;
3565 acl_main_t *am = &acl_main;
3567 u32 show_bihash_verbose = 0;
3568 u32 show_session_thread_id = ~0;
3569 u32 show_session_session_index = ~0;
3570 (void) unformat (input, "thread %u index %u", &show_session_thread_id,
3571 &show_session_session_index);
3572 (void) unformat (input, "verbose %u", &show_bihash_verbose);
3574 acl_plugin_show_sessions (am, show_session_thread_id,
3575 show_session_session_index);
3576 show_fa_sessions_hash (vm, show_bihash_verbose);
3581 acl_plugin_show_tables_mask_type (acl_main_t * am)
3583 vlib_main_t *vm = am->vlib_main;
3584 ace_mask_type_entry_t *mte;
3586 vlib_cli_output (vm, "Mask-type entries:");
3588 pool_foreach(mte, am->ace_mask_type_pool,
3590 vlib_cli_output(vm, " %3d: %016llx %016llx %016llx %016llx %016llx %016llx refcount %d",
3591 mte - am->ace_mask_type_pool,
3592 mte->mask.kv.key[0], mte->mask.kv.key[1], mte->mask.kv.key[2],
3593 mte->mask.kv.key[3], mte->mask.kv.key[4], mte->mask.kv.value, mte->refcount);
3599 acl_plugin_show_tables_acl_hash_info (acl_main_t * am, u32 acl_index)
3601 vlib_main_t *vm = am->vlib_main;
3604 vlib_cli_output (vm, "Mask-ready ACL representations\n");
3605 for (i = 0; i < vec_len (am->hash_acl_infos); i++)
3607 if ((acl_index != ~0) && (acl_index != i))
3611 hash_acl_info_t *ha = &am->hash_acl_infos[i];
3612 vlib_cli_output (vm, "acl-index %u bitmask-ready layout\n", i);
3613 vlib_cli_output (vm, " applied inbound on sw_if_index list: %U\n",
3614 format_vec32, ha->inbound_sw_if_index_list, "%d");
3615 vlib_cli_output (vm, " applied outbound on sw_if_index list: %U\n",
3616 format_vec32, ha->outbound_sw_if_index_list, "%d");
3617 vlib_cli_output (vm, " mask type index bitmap: %U\n",
3618 format_bitmap_hex, ha->mask_type_index_bitmap);
3619 for (j = 0; j < vec_len (ha->rules); j++)
3621 hash_ace_info_t *pa = &ha->rules[j];
3622 m = (u64 *) & pa->match;
3623 vlib_cli_output (vm,
3624 " %4d: %016llx %016llx %016llx %016llx %016llx %016llx mask index %d acl %d rule %d action %d src/dst portrange not ^2: %d,%d\n",
3625 j, m[0], m[1], m[2], m[3], m[4], m[5],
3626 pa->mask_type_index, pa->acl_index, pa->ace_index,
3627 pa->action, pa->src_portrange_not_powerof2,
3628 pa->dst_portrange_not_powerof2);
3634 acl_plugin_print_pae (vlib_main_t * vm, int j, applied_hash_ace_entry_t * pae)
3636 vlib_cli_output (vm,
3637 " %4d: acl %d rule %d action %d bitmask-ready rule %d next %d prev %d tail %d hitcount %lld",
3638 j, pae->acl_index, pae->ace_index, pae->action,
3639 pae->hash_ace_info_index, pae->next_applied_entry_index,
3640 pae->prev_applied_entry_index,
3641 pae->tail_applied_entry_index, pae->hitcount);
3645 acl_plugin_show_tables_applied_info (acl_main_t * am, u32 sw_if_index)
3647 vlib_main_t *vm = am->vlib_main;
3649 vlib_cli_output (vm, "Applied lookup entries for interfaces");
3652 (swi < vec_len (am->input_applied_hash_acl_info_by_sw_if_index))
3653 || (swi < vec_len (am->output_applied_hash_acl_info_by_sw_if_index))
3654 || (swi < vec_len (am->input_hash_entry_vec_by_sw_if_index))
3655 || (swi < vec_len (am->output_hash_entry_vec_by_sw_if_index)); swi++)
3657 if ((sw_if_index != ~0) && (sw_if_index != swi))
3661 vlib_cli_output (vm, "sw_if_index %d:", swi);
3662 if (swi < vec_len (am->input_applied_hash_acl_info_by_sw_if_index))
3664 applied_hash_acl_info_t *pal =
3665 &am->input_applied_hash_acl_info_by_sw_if_index[swi];
3666 vlib_cli_output (vm, " input lookup mask_type_index_bitmap: %U",
3667 format_bitmap_hex, pal->mask_type_index_bitmap);
3668 vlib_cli_output (vm, " input applied acls: %U", format_vec32,
3669 pal->applied_acls, "%d");
3671 if (swi < vec_len (am->input_hash_entry_vec_by_sw_if_index))
3673 vlib_cli_output (vm, " input lookup applied entries:");
3675 j < vec_len (am->input_hash_entry_vec_by_sw_if_index[swi]);
3678 acl_plugin_print_pae (vm, j,
3679 &am->input_hash_entry_vec_by_sw_if_index
3684 if (swi < vec_len (am->output_applied_hash_acl_info_by_sw_if_index))
3686 applied_hash_acl_info_t *pal =
3687 &am->output_applied_hash_acl_info_by_sw_if_index[swi];
3688 vlib_cli_output (vm, " output lookup mask_type_index_bitmap: %U",
3689 format_bitmap_hex, pal->mask_type_index_bitmap);
3690 vlib_cli_output (vm, " output applied acls: %U", format_vec32,
3691 pal->applied_acls, "%d");
3693 if (swi < vec_len (am->output_hash_entry_vec_by_sw_if_index))
3695 vlib_cli_output (vm, " output lookup applied entries:");
3697 j < vec_len (am->output_hash_entry_vec_by_sw_if_index[swi]);
3700 acl_plugin_print_pae (vm, j,
3701 &am->output_hash_entry_vec_by_sw_if_index
3709 acl_plugin_show_tables_bihash (acl_main_t * am, u32 show_bihash_verbose)
3711 vlib_main_t *vm = am->vlib_main;
3712 show_hash_acl_hash (vm, am, show_bihash_verbose);
3715 static clib_error_t *
3716 acl_show_aclplugin_tables_fn (vlib_main_t * vm,
3717 unformat_input_t * input,
3718 vlib_cli_command_t * cmd)
3720 clib_error_t *error = 0;
3721 acl_main_t *am = &acl_main;
3724 u32 sw_if_index = ~0;
3725 int show_acl_hash_info = 0;
3726 int show_applied_info = 0;
3727 int show_mask_type = 0;
3728 int show_bihash = 0;
3729 u32 show_bihash_verbose = 0;
3731 if (unformat (input, "acl"))
3733 show_acl_hash_info = 1;
3734 /* mask-type is handy to see as well right there */
3736 unformat (input, "index %u", &acl_index);
3738 else if (unformat (input, "applied"))
3740 show_applied_info = 1;
3741 unformat (input, "sw_if_index %u", &sw_if_index);
3743 else if (unformat (input, "mask"))
3747 else if (unformat (input, "hash"))
3750 unformat (input, "verbose %u", &show_bihash_verbose);
3754 (show_mask_type || show_acl_hash_info || show_applied_info
3757 /* if no qualifiers specified, show all */
3759 show_acl_hash_info = 1;
3760 show_applied_info = 1;
3764 acl_plugin_show_tables_mask_type (am);
3765 if (show_acl_hash_info)
3766 acl_plugin_show_tables_acl_hash_info (am, acl_index);
3767 if (show_applied_info)
3768 acl_plugin_show_tables_applied_info (am, sw_if_index);
3770 acl_plugin_show_tables_bihash (am, show_bihash_verbose);
3775 static clib_error_t *
3776 acl_clear_aclplugin_fn (vlib_main_t * vm,
3777 unformat_input_t * input, vlib_cli_command_t * cmd)
3779 clib_error_t *error = 0;
3780 acl_main_t *am = &acl_main;
3781 vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index,
3782 ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX, ~0);
3787 VLIB_CLI_COMMAND (aclplugin_set_command, static) = {
3788 .path = "set acl-plugin",
3789 .short_help = "set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>",
3790 .function = acl_set_aclplugin_fn,
3793 VLIB_CLI_COMMAND (aclplugin_show_acl_command, static) = {
3794 .path = "show acl-plugin acl",
3795 .short_help = "show acl-plugin acl [index N]",
3796 .function = acl_show_aclplugin_acl_fn,
3799 VLIB_CLI_COMMAND (aclplugin_show_decode_5tuple_command, static) = {
3800 .path = "show acl-plugin decode 5tuple",
3801 .short_help = "show acl-plugin decode 5tuple XXXX XXXX XXXX XXXX XXXX XXXX",
3802 .function = acl_show_aclplugin_decode_5tuple_fn,
3805 VLIB_CLI_COMMAND (aclplugin_show_interface_command, static) = {
3806 .path = "show acl-plugin interface",
3807 .short_help = "show acl-plugin interface [sw_if_index N] [acl]",
3808 .function = acl_show_aclplugin_interface_fn,
3811 VLIB_CLI_COMMAND (aclplugin_show_memory_command, static) = {
3812 .path = "show acl-plugin memory",
3813 .short_help = "show acl-plugin memory",
3814 .function = acl_show_aclplugin_memory_fn,
3817 VLIB_CLI_COMMAND (aclplugin_show_sessions_command, static) = {
3818 .path = "show acl-plugin sessions",
3819 .short_help = "show acl-plugin sessions",
3820 .function = acl_show_aclplugin_sessions_fn,
3823 VLIB_CLI_COMMAND (aclplugin_show_tables_command, static) = {
3824 .path = "show acl-plugin tables",
3825 .short_help = "show acl-plugin tables [ acl [index N] | applied [ sw_if_index N ] | mask | hash [verbose N] ]",
3826 .function = acl_show_aclplugin_tables_fn,
3829 VLIB_CLI_COMMAND (aclplugin_show_macip_acl_command, static) = {
3830 .path = "show acl-plugin macip acl",
3831 .short_help = "show acl-plugin macip acl",
3832 .function = acl_show_aclplugin_macip_acl_fn,
3835 VLIB_CLI_COMMAND (aclplugin_show_macip_interface_command, static) = {
3836 .path = "show acl-plugin macip interface",
3837 .short_help = "show acl-plugin macip interface",
3838 .function = acl_show_aclplugin_macip_interface_fn,
3841 VLIB_CLI_COMMAND (aclplugin_clear_command, static) = {
3842 .path = "clear acl-plugin sessions",
3843 .short_help = "clear acl-plugin sessions",
3844 .function = acl_clear_aclplugin_fn,
3848 static clib_error_t *
3849 acl_plugin_config (vlib_main_t * vm, unformat_input_t * input)
3851 acl_main_t *am = &acl_main;
3852 u32 conn_table_hash_buckets;
3853 u32 conn_table_hash_memory_size;
3854 u32 conn_table_max_entries;
3857 u32 hash_lookup_hash_buckets;
3858 u32 hash_lookup_hash_memory;
3860 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3863 (input, "connection hash buckets %d", &conn_table_hash_buckets))
3864 am->fa_conn_table_hash_num_buckets = conn_table_hash_buckets;
3865 else if (unformat (input, "connection hash memory %d",
3866 &conn_table_hash_memory_size))
3867 am->fa_conn_table_hash_memory_size = conn_table_hash_memory_size;
3868 else if (unformat (input, "connection count max %d",
3869 &conn_table_max_entries))
3870 am->fa_conn_table_max_entries = conn_table_max_entries;
3871 else if (unformat (input, "main heap size %d", &main_heap_size))
3872 am->acl_mheap_size = main_heap_size;
3873 else if (unformat (input, "hash lookup heap size %d", &hash_heap_size))
3874 am->hash_lookup_mheap_size = hash_heap_size;
3875 else if (unformat (input, "hash lookup hash buckets %d",
3876 &hash_lookup_hash_buckets))
3877 am->hash_lookup_hash_buckets = hash_lookup_hash_buckets;
3878 else if (unformat (input, "hash lookup hash memory %d",
3879 &hash_lookup_hash_memory))
3880 am->hash_lookup_hash_memory = hash_lookup_hash_memory;
3882 return clib_error_return (0, "unknown input '%U'",
3883 format_unformat_error, input);
3888 VLIB_CONFIG_FUNCTION (acl_plugin_config, "acl-plugin");
3890 static clib_error_t *
3891 acl_init (vlib_main_t * vm)
3893 acl_main_t *am = &acl_main;
3894 clib_error_t *error = 0;
3895 memset (am, 0, sizeof (*am));
3897 am->vnet_main = vnet_get_main ();
3899 u8 *name = format (0, "acl_%08x%c", api_version, 0);
3901 /* Ask for a correctly-sized block of API message decode slots */
3902 am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
3903 VL_MSG_FIRST_AVAILABLE);
3905 error = acl_plugin_api_hookup (vm);
3907 /* Add our API messages to the global name_crc hash table */
3908 setup_message_id_table (am, &api_main);
3912 acl_setup_fa_nodes ();
3914 am->acl_mheap_size = ACL_FA_DEFAULT_HEAP_SIZE;
3915 am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
3917 am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
3918 am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
3920 am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
3921 TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
3922 am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
3923 TCP_SESSION_IDLE_TIMEOUT_SEC;
3924 am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
3925 UDP_SESSION_IDLE_TIMEOUT_SEC;
3927 am->fa_conn_table_hash_num_buckets =
3928 ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
3929 am->fa_conn_table_hash_memory_size =
3930 ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
3931 am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
3932 vlib_thread_main_t *tm = vlib_get_thread_main ();
3933 vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
3937 for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
3939 acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
3940 vec_validate (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1);
3941 vec_validate (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1);
3942 for (tt = 0; tt < ACL_N_TIMEOUTS; tt++)
3944 pw->fa_conn_list_head[tt] = ~0;
3945 pw->fa_conn_list_tail[tt] = ~0;
3950 am->fa_min_deleted_sessions_per_interval =
3951 ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
3952 am->fa_max_deleted_sessions_per_interval =
3953 ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
3954 am->fa_cleaner_wait_time_increment =
3955 ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
3957 am->fa_cleaner_cnt_delete_by_sw_index = 0;
3958 am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
3959 am->fa_cleaner_cnt_unknown_event = 0;
3960 am->fa_cleaner_cnt_timer_restarted = 0;
3961 am->fa_cleaner_cnt_wait_with_timeout = 0;
3964 #define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
3967 am->l4_match_nonfirst_fragment = 1;
3969 /* use the new fancy hash-based matching */
3970 am->use_hash_acl_matching = 1;
3975 VLIB_INIT_FUNCTION (acl_init);
3979 * fd.io coding-style-patch-verification: ON
3982 * eval: (c-set-style "gnu")