From c1f87942da3f6daeb4c30002929828e86035cee2 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Sat, 6 Oct 2018 09:26:02 +0200 Subject: acl-plugin: use the L2 feature arc infrastructure instead of L2 classifier for plumbing This makes ACL plugin use the new feature arcs, which slightly increases performance. Since for ethertype whitelisting we were using the L2 classifier, to retain the functionality, make a simple node doing that, and plug it into non-ip L2 feature arc whenever needed. Change-Id: I3add377a6c790117dd3fd056e5615cb4c4438cf4 Signed-off-by: Andrew Yourtchenko --- src/plugins/acl/acl.c | 699 +++------------------------------------ src/plugins/acl/acl.h | 13 - src/plugins/acl/dataplane_node.c | 291 ++++++++++++++-- test/test_acl_plugin.py | 8 + 4 files changed, 312 insertions(+), 699 deletions(-) diff --git a/src/plugins/acl/acl.c b/src/plugins/acl/acl.c index 866c6ffc5f0..2af2d7a8b70 100644 --- a/src/plugins/acl/acl.c +++ b/src/plugins/acl/acl.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -489,86 +490,6 @@ acl_del_list (u32 acl_list_index) return 0; } -/* Some aids in ASCII graphing the content */ -#define XX "\377" -#define __ "\000" -#define _(x) -#define v -/* *INDENT-OFF* */ - -u8 ip4_5tuple_mask[] = - _(" dmac smac etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v - _(" v ihl totlen ") - _(0x0000) - __ __ __ __ - _(" ident fl+fo ") - _(0x0004) - __ __ __ __ - _(" ttl pr checksum ") - _(0x0008) - __ XX __ __ - _(" src address ") - _(0x000C) - XX XX XX XX - _(" dst address ") - _(0x0010) - XX XX XX XX - _("L4 T/U sport dport ") - _(tcpudp) - XX XX XX XX - _(padpad) - __ __ __ __ - _(padpad) - __ __ __ __ - _(padeth) - __ __; - - u8 ip6_5tuple_mask[] = - _(" dmac smac etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v __ __ v - _(" v tc + flow ") - _(0x0000) __ __ __ __ - _(" plen nh hl ") - _(0x0004) __ __ XX __ - _(" src address ") - _(0x0008) XX XX XX XX - _(0x000C) XX XX XX XX - _(0x0010) XX XX XX XX - _(0x0014) XX XX XX XX - _(" dst address ") - _(0x0018) XX XX XX XX - _(0x001C) XX XX XX XX - _(0x0020) XX XX XX XX - _(0x0024) XX XX XX XX - _("L4T/U sport dport ") - _(tcpudp) XX XX XX XX _(padpad) __ __ __ __ _(padeth) __ __; - - u8 dot1q_5tuple_mask[] = - _(" dmac smac dot1q etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __ v XX XX v - _(padpad) __ __ __ __ - _(padpad) __ __ __ __ - _(padpad) __ __ __ __ - _(padeth) __ __; - - u8 dot1ad_5tuple_mask[] = - _(" dmac smac dot1ad dot1q etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __ XX XX __ __ v XX XX v - _(padpad) __ __ __ __ - _(padpad) __ __ __ __ - _(padeth) __ __; - - u8 ethertype_mask[] = - _(" dmac smac etype ") - _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __; - -/* *INDENT-ON* */ -#undef XX -#undef __ -#undef _ -#undef v - static int count_skip (u8 * p, u32 size) { @@ -584,33 +505,6 @@ count_skip (u8 * p, u32 size) return (p64 - (u64 *) p) / 2; } -static int -acl_classify_add_del_table_tiny (vnet_classify_main_t * cm, u8 * mask, - u32 mask_len, u32 next_table_index, - u32 miss_next_index, u32 * table_index, - int is_add) -{ - u32 nbuckets = 1; - u32 memory_size = 2 << 13; - u32 skip = count_skip (mask, mask_len); - u32 match = (mask_len / 16) - skip; - u8 *skip_mask_ptr = mask + 16 * skip; - u32 current_data_flag = 0; - int current_data_offset = 0; - - if (0 == match) - match = 1; - void *oldheap = clib_mem_set_heap (cm->vlib_main->heap_base); - int ret = vnet_classify_add_del_table (cm, skip_mask_ptr, nbuckets, - memory_size, skip, match, - next_table_index, miss_next_index, - table_index, current_data_flag, - current_data_offset, is_add, - 1 /* delete_chain */ ); - clib_mem_set_heap (oldheap); - return ret; -} - static int acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask, u32 mask_len, u32 next_table_index, @@ -639,503 +533,14 @@ acl_classify_add_del_table_small (vnet_classify_main_t * cm, u8 * mask, return ret; } -static int -acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - u32 dot1q_table_index = ~0; - u32 dot1ad_table_index = ~0; - u32 etype_table_index = ~0; - void *oldheap = acl_set_heap (am); - - vec_validate_init_empty (am->acl_ip4_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_ip6_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_dot1q_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_dot1ad_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_etype_input_classify_table_by_sw_if_index, - sw_if_index, ~0); - - /* switch to global heap while calling vnet_* functions */ - clib_mem_set_heap (cm->vlib_main->heap_base); - vnet_l2_input_classify_enable_disable (sw_if_index, 0); - - if (am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip4_table_index = - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip4, - &ip4_table_index, 0); - } - if (am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip6_table_index = - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip6, - &ip6_table_index, 0); - } - if (am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - dot1q_table_index = - am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - ~0, &dot1q_table_index, 0); - } - if (am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - dot1ad_table_index = - am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - } - if (am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - etype_table_index = - am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index]; - am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ethertype_mask, - sizeof (ethertype_mask) - 1, ~0, - ~0, &etype_table_index, 0); - } - clib_mem_set_heap (oldheap); - return 0; -} - -static int -acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - u32 dot1q_table_index = ~0; - u32 dot1ad_table_index = ~0; - u32 etype_table_index = ~0; - void *oldheap = acl_set_heap (am); - - vec_validate_init_empty (am->acl_ip4_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_ip6_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty (am->acl_dot1q_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - vec_validate_init_empty - (am->acl_dot1ad_output_classify_table_by_sw_if_index, sw_if_index, ~0); - vec_validate_init_empty (am->acl_etype_output_classify_table_by_sw_if_index, - sw_if_index, ~0); - - /* switch to global heap while calling vnet_* functions */ - clib_mem_set_heap (cm->vlib_main->heap_base); - - vnet_l2_output_classify_enable_disable (sw_if_index, 0); - - if (am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip4_table_index = - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip4, - &ip4_table_index, 0); - } - if (am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - ip6_table_index = - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip6, - &ip6_table_index, 0); - } - if (am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - dot1q_table_index = - am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - ~0, &dot1q_table_index, 0); - } - if (am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - dot1ad_table_index = - am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - } - if (am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] != ~0) - { - etype_table_index = - am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index]; - am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] = ~0; - acl_classify_add_del_table_tiny (cm, ethertype_mask, - sizeof (ethertype_mask) - 1, ~0, - ~0, &etype_table_index, 0); - } - clib_mem_set_heap (oldheap); - return 0; -} - -static void -acl_add_vlan_session (acl_main_t * am, u32 table_index, u8 is_output, - u8 is_dot1ad, u8 is_ip6) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u8 *match; - u32 next_acl; - u8 idx; - u8 session_idx; - - if (is_ip6) - { - next_acl = - (is_output) ? am-> - l2_output_classify_next_acl_ip6 : am->l2_input_classify_next_acl_ip6; - } - else - { - next_acl = - (is_output) ? am-> - l2_output_classify_next_acl_ip4 : am->l2_input_classify_next_acl_ip4; - } - match = (is_dot1ad) ? dot1ad_5tuple_mask : dot1q_5tuple_mask; - idx = (is_dot1ad) ? 20 : 16; - if (is_dot1ad) - { - /* 802.1ad ethertype */ - match[12] = 0x88; - match[13] = 0xa8; - /* 802.1q ethertype */ - match[16] = 0x81; - match[17] = 0x00; - } - else - { - /* 802.1q ethertype */ - match[12] = 0x81; - match[13] = 0x00; - } - - /* add sessions to vlan tables per ethernet_type */ - if (is_ip6) - { - match[idx] = 0x86; - match[idx + 1] = 0xdd; - session_idx = 1; - } - else - { - match[idx] = 0x08; - match[idx + 1] = 0x00; - session_idx = 0; - } - vnet_classify_add_del_session (cm, table_index, match, next_acl, - session_idx, 0, 0, 0, 1); - /* reset the mask back to being a mask */ - match[idx] = 0xff; - match[idx + 1] = 0xff; - match[12] = 0xff; - match[13] = 0xff; - if (is_dot1ad) - { - match[16] = 0xff; - match[17] = 0xff; - } -} - static int intf_has_etype_whitelist (acl_main_t * am, u32 sw_if_index, int is_input) { u16 **v = is_input ? am->input_etype_whitelist_by_sw_if_index : am->output_etype_whitelist_by_sw_if_index; - return ((vec_len (v) > sw_if_index) && vec_elt (v, sw_if_index)); -} - -static int -etype_whitelist_add_sessions (acl_main_t * am, u32 sw_if_index, int is_input, - u32 etype_table_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u16 **v = is_input - ? am->input_etype_whitelist_by_sw_if_index - : am->output_etype_whitelist_by_sw_if_index; - u8 *match = ethertype_mask; - - int i; - int rv = 0; - u16 *whitelist = vec_elt (v, sw_if_index); - u32 next = ~0; /* permit */ - for (i = 0; i < vec_len (whitelist); i++) - { - /* big-endian */ - match[12] = (whitelist[i] >> 8) & 0xff; - match[13] = whitelist[i] & 0xff; - rv = rv - || vnet_classify_add_del_session (cm, etype_table_index, match, next, - whitelist[i], 0, 0, 0, 1); - } - - /* restore the mask */ - match[12] = 0xff; - match[13] = 0xff; - return rv; -} - -static int -acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - u32 dot1q_table_index = ~0; - u32 dot1ad_table_index = ~0; - u32 etype_table_index = ~0; - int rv; - - void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base); - - /* in case there were previous tables attached */ - acl_unhook_l2_input_classify (am, sw_if_index); - rv = - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip4, - &ip4_table_index, 1); - if (rv) - goto done; - - rv = - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip6, - &ip6_table_index, 1); - if (rv) - { - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip4, - &ip4_table_index, 0); - goto done; - } - - if (intf_has_etype_whitelist (am, sw_if_index, 1)) - { - acl_classify_add_del_table_tiny (cm, ethertype_mask, sizeof (ethertype_mask) - 1, ~0, 0, /* drop if no match */ - &etype_table_index, 1); - etype_whitelist_add_sessions (am, sw_if_index, 1, etype_table_index); - } - - rv = - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, - etype_table_index, ~0, - &dot1ad_table_index, 1); - rv = - acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask, - sizeof (dot1q_5tuple_mask) - 1, - dot1ad_table_index, ~0, - &dot1q_table_index, 1); - if (rv) - { - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip6, - &ip6_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip4, - &ip4_table_index, 0); - goto done; - } - - rv = - vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index, - ip6_table_index, dot1q_table_index); - - if (rv) - { - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip4, - &ip4_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_input_classify_next_acl_ip6, - &ip6_table_index, 0); - acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask, - sizeof (dot1q_5tuple_mask) - 1, ~0, - ~0, &dot1q_table_index, 0); - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - goto done; - } - - /* add sessions to vlan tables per ethernet_type */ - acl_add_vlan_session (am, dot1q_table_index, 0, 0, 0); - acl_add_vlan_session (am, dot1q_table_index, 0, 0, 1); - acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 0); - acl_add_vlan_session (am, dot1ad_table_index, 0, 1, 1); - - am->acl_ip4_input_classify_table_by_sw_if_index[sw_if_index] = - ip4_table_index; - am->acl_ip6_input_classify_table_by_sw_if_index[sw_if_index] = - ip6_table_index; - am->acl_dot1q_input_classify_table_by_sw_if_index[sw_if_index] = - dot1q_table_index; - am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] = - dot1ad_table_index; - am->acl_dot1ad_input_classify_table_by_sw_if_index[sw_if_index] = - dot1ad_table_index; - am->acl_etype_input_classify_table_by_sw_if_index[sw_if_index] = - etype_table_index; - - vnet_l2_input_classify_enable_disable (sw_if_index, 1); -done: - clib_mem_set_heap (prevheap); - return rv; -} - -static int -acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index) -{ - vnet_classify_main_t *cm = &vnet_classify_main; - u32 ip4_table_index = ~0; - u32 ip6_table_index = ~0; - u32 dot1q_table_index = ~0; - u32 dot1ad_table_index = ~0; - u32 etype_table_index = ~0; - int rv; - - void *prevheap = clib_mem_set_heap (cm->vlib_main->heap_base); - - /* in case there were previous tables attached */ - acl_unhook_l2_output_classify (am, sw_if_index); - rv = - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip4, - &ip4_table_index, 1); - if (rv) - goto done; - rv = - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip6, - &ip6_table_index, 1); - if (rv) - { - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip4, - &ip4_table_index, 0); - goto done; - } - - if (intf_has_etype_whitelist (am, sw_if_index, 0)) - { - acl_classify_add_del_table_tiny (cm, ethertype_mask, sizeof (ethertype_mask) - 1, ~0, 0, /* drop if no match */ - &etype_table_index, 1); - etype_whitelist_add_sessions (am, sw_if_index, 0, etype_table_index); - } - - - rv = - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, - etype_table_index, ~0, - &dot1ad_table_index, 1); - rv = - acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask, - sizeof (dot1q_5tuple_mask) - 1, - dot1ad_table_index, ~0, - &dot1q_table_index, 1); - if (rv) - { - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip6, - &ip6_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip4, - &ip4_table_index, 0); - goto done; - } - - rv = - vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index, - ip6_table_index, dot1q_table_index); -/* - clib_warning - ("ACL enabling on interface sw_if_index %d, setting tables to the following: ip4: %d ip6: %d\n", - sw_if_index, ip4_table_index, ip6_table_index); -*/ - if (rv) - { - acl_classify_add_del_table_tiny (cm, ip6_5tuple_mask, - sizeof (ip6_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip6, - &ip6_table_index, 0); - acl_classify_add_del_table_tiny (cm, ip4_5tuple_mask, - sizeof (ip4_5tuple_mask) - 1, ~0, - am->l2_output_classify_next_acl_ip4, - &ip4_table_index, 0); - acl_classify_add_del_table_tiny (cm, dot1q_5tuple_mask, - sizeof (dot1q_5tuple_mask) - 1, ~0, - ~0, &dot1q_table_index, 0); - acl_classify_add_del_table_tiny (cm, dot1ad_5tuple_mask, - sizeof (dot1ad_5tuple_mask) - 1, ~0, - ~0, &dot1ad_table_index, 0); - goto done; - } - - /* add sessions to vlan tables per ethernet_type */ - acl_add_vlan_session (am, dot1q_table_index, 1, 0, 0); - acl_add_vlan_session (am, dot1q_table_index, 1, 0, 1); - acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 0); - acl_add_vlan_session (am, dot1ad_table_index, 1, 1, 1); - - am->acl_ip4_output_classify_table_by_sw_if_index[sw_if_index] = - ip4_table_index; - am->acl_ip6_output_classify_table_by_sw_if_index[sw_if_index] = - ip6_table_index; - am->acl_dot1q_output_classify_table_by_sw_if_index[sw_if_index] = - dot1q_table_index; - am->acl_dot1ad_output_classify_table_by_sw_if_index[sw_if_index] = - dot1ad_table_index; - am->acl_etype_output_classify_table_by_sw_if_index[sw_if_index] = - etype_table_index; - - vnet_l2_output_classify_enable_disable (sw_if_index, 1); -done: - clib_mem_set_heap (prevheap); - return rv; + u16 *whitelist = (vec_len (v) > sw_if_index) ? vec_elt (v, sw_if_index) : 0; + return vec_len (whitelist) > 0; } static void @@ -1166,14 +571,22 @@ acl_interface_in_enable_disable (acl_main_t * am, u32 sw_if_index, acl_fa_enable_disable (sw_if_index, 1, enable_disable); - if (enable_disable) - { - rv = acl_hook_l2_input_classify (am, sw_if_index); - } - else - { - rv = acl_unhook_l2_input_classify (am, sw_if_index); - } + void *oldheap = clib_mem_set_heap (am->vlib_main->heap_base); + rv = vnet_l2_feature_enable_disable ("l2-input-ip4", "acl-plugin-in-ip4-l2", + sw_if_index, enable_disable, 0, 0); + if (rv) + clib_error ("Could not enable on input"); + rv = vnet_l2_feature_enable_disable ("l2-input-ip6", "acl-plugin-in-ip6-l2", + sw_if_index, enable_disable, 0, 0); + if (rv) + clib_error ("Could not enable on input"); + + if (intf_has_etype_whitelist (am, sw_if_index, 1)) + vnet_l2_feature_enable_disable ("l2-input-nonip", + "acl-plugin-in-nonip-l2", sw_if_index, + enable_disable, 0, 0); + + clib_mem_set_heap (oldheap); am->in_acl_on_sw_if_index = clib_bitmap_set (am->in_acl_on_sw_if_index, sw_if_index, enable_disable); @@ -1185,7 +598,7 @@ static int acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index, int enable_disable) { - int rv; + int rv = 0; /* Utterly wrong? */ if (pool_is_free_index (am->vnet_main->interface_main.sw_interfaces, @@ -1198,14 +611,24 @@ acl_interface_out_enable_disable (acl_main_t * am, u32 sw_if_index, acl_fa_enable_disable (sw_if_index, 0, enable_disable); - if (enable_disable) - { - rv = acl_hook_l2_output_classify (am, sw_if_index); - } - else - { - rv = acl_unhook_l2_output_classify (am, sw_if_index); - } + void *oldheap = clib_mem_set_heap (am->vlib_main->heap_base); + rv = + vnet_l2_feature_enable_disable ("l2-output-ip4", "acl-plugin-out-ip4-l2", + sw_if_index, enable_disable, 0, 0); + if (rv) + clib_error ("Could not enable on output"); + rv = + vnet_l2_feature_enable_disable ("l2-output-ip6", "acl-plugin-out-ip6-l2", + sw_if_index, enable_disable, 0, 0); + if (rv) + clib_error ("Could not enable on output"); + if (intf_has_etype_whitelist (am, sw_if_index, 0)) + vnet_l2_feature_enable_disable ("l2-output-nonip", + "acl-plugin-out-nonip-l2", sw_if_index, + enable_disable, 0, 0); + + + clib_mem_set_heap (oldheap); am->out_acl_on_sw_if_index = clib_bitmap_set (am->out_acl_on_sw_if_index, sw_if_index, enable_disable); @@ -3114,50 +2537,6 @@ setup_message_id_table (acl_main_t * am, api_main_t * apim) #undef _ } -static void -acl_setup_fa_nodes (void) -{ - vlib_main_t *vm = vlib_get_main (); - acl_main_t *am = &acl_main; - vlib_node_t *n, *n4, *n6; - - n = vlib_get_node_by_name (vm, (u8 *) "l2-input-classify"); - n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip4-l2"); - n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-in-ip6-l2"); - - - am->l2_input_classify_next_acl_ip4 = - vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0); - am->l2_input_classify_next_acl_ip6 = - vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0); - - feat_bitmap_init_next_nodes (vm, n4->index, L2INPUT_N_FEAT, - l2input_get_feat_names (), - am->fa_acl_in_ip4_l2_node_feat_next_node_index); - - feat_bitmap_init_next_nodes (vm, n6->index, L2INPUT_N_FEAT, - l2input_get_feat_names (), - am->fa_acl_in_ip6_l2_node_feat_next_node_index); - - - n = vlib_get_node_by_name (vm, (u8 *) "l2-output-classify"); - n4 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip4-l2"); - n6 = vlib_get_node_by_name (vm, (u8 *) "acl-plugin-out-ip6-l2"); - - am->l2_output_classify_next_acl_ip4 = - vlib_node_add_next_with_slot (vm, n->index, n4->index, ~0); - am->l2_output_classify_next_acl_ip6 = - vlib_node_add_next_with_slot (vm, n->index, n6->index, ~0); - - feat_bitmap_init_next_nodes (vm, n4->index, L2OUTPUT_N_FEAT, - l2output_get_feat_names (), - am->fa_acl_out_ip4_l2_node_feat_next_node_index); - - feat_bitmap_init_next_nodes (vm, n6->index, L2OUTPUT_N_FEAT, - l2output_get_feat_names (), - am->fa_acl_out_ip6_l2_node_feat_next_node_index); -} - static void acl_set_timeout_sec (int timeout_type, u32 value) { @@ -4180,8 +3559,6 @@ acl_init (vlib_main_t * vm) if (error) return error; - acl_setup_fa_nodes (); - am->acl_mheap_size = 0; /* auto size when initializing */ am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE; diff --git a/src/plugins/acl/acl.h b/src/plugins/acl/acl.h index c17946a9719..1d1ee442304 100644 --- a/src/plugins/acl/acl.h +++ b/src/plugins/acl/acl.h @@ -251,19 +251,6 @@ typedef struct { /* how many sessions went into purgatory */ u64 fa_session_total_deactivations; - /* L2 datapath glue */ - - /* next indices within L2 classifiers for ip4/ip6 fa L2 nodes */ - u32 l2_input_classify_next_acl_ip4; - u32 l2_input_classify_next_acl_ip6; - u32 l2_output_classify_next_acl_ip4; - u32 l2_output_classify_next_acl_ip6; - /* next node indices for L2 dispatch */ - u32 fa_acl_in_ip4_l2_node_feat_next_node_index[32]; - u32 fa_acl_in_ip6_l2_node_feat_next_node_index[32]; - u32 fa_acl_out_ip4_l2_node_feat_next_node_index[32]; - u32 fa_acl_out_ip6_l2_node_feat_next_node_index[32]; - /* EH values that we can skip over */ uword *fa_ipv6_known_eh_bitmap; diff --git a/src/plugins/acl/dataplane_node.c b/src/plugins/acl/dataplane_node.c index 79ee5010c26..fef355138e0 100644 --- a/src/plugins/acl/dataplane_node.c +++ b/src/plugins/acl/dataplane_node.c @@ -66,6 +66,232 @@ typedef enum /* *INDENT-ON* */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u16 ethertype; +} nonip_in_out_trace_t; + +/* packet trace format function */ +static u8 * +format_nonip_in_out_trace (u8 * s, u32 is_output, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nonip_in_out_trace_t *t = va_arg (*args, nonip_in_out_trace_t *); + + s = format (s, "%s: sw_if_index %d next_index %x ethertype %x", + is_output ? "OUT-ETHER-WHITELIST" : "IN-ETHER-WHITELIST", + t->sw_if_index, t->next_index, t->ethertype); + return s; +} + +static u8 * +format_l2_nonip_in_trace (u8 * s, va_list * args) +{ + return format_nonip_in_out_trace (s, 0, args); +} + +static u8 * +format_l2_nonip_out_trace (u8 * s, va_list * args) +{ + return format_nonip_in_out_trace (s, 1, args); +} + +#define foreach_nonip_in_error \ +_(DROP, "dropped inbound non-whitelisted non-ip packets") \ +_(PERMIT, "permitted inbound whitelisted non-ip packets") \ + + +#define foreach_nonip_out_error \ +_(DROP, "dropped outbound non-whitelisted non-ip packets") \ +_(PERMIT, "permitted outbound whitelisted non-ip packets") \ + + +/* *INDENT-OFF* */ + +typedef enum +{ +#define _(sym,str) FA_IN_NONIP_ERROR_##sym, + foreach_nonip_in_error +#undef _ + FA_IN_NONIP_N_ERROR, +} l2_in_feat_arc_error_t; + +static char *fa_in_nonip_error_strings[] = { +#define _(sym,string) string, + foreach_nonip_in_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) FA_OUT_NONIP_ERROR_##sym, + foreach_nonip_out_error +#undef _ + FA_OUT_NONIP_N_ERROR, +} l2_out_feat_arc_error_t; + +static char *fa_out_nonip_error_strings[] = { +#define _(sym,string) string, + foreach_nonip_out_error +#undef _ +}; +/* *INDENT-ON* */ + + +always_inline int +is_permitted_ethertype (acl_main_t * am, int sw_if_index0, int is_output, + u16 ethertype) +{ + u16 **v = is_output + ? am->output_etype_whitelist_by_sw_if_index + : am->input_etype_whitelist_by_sw_if_index; + u16 *whitelist = vec_elt (v, sw_if_index0); + int i; + + if (vec_len (whitelist) == 0) + return 1; + + for (i = 0; i < vec_len (whitelist); i++) + if (whitelist[i] == ethertype) + return 1; + return 0; +} + +#define get_u16(addr) ( *((u16 *)(addr)) ) + +always_inline uword +nonip_in_out_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_output, vlib_node_registration_t * fa_node) +{ + acl_main_t *am = &acl_main; + u32 n_left, *from; + u16 nexts[VLIB_FRAME_SIZE], *next; + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + vlib_node_runtime_t *error_node; + + from = vlib_frame_vector_args (frame); + error_node = vlib_node_get_runtime (vm, fa_node->index); + vlib_get_buffers (vm, from, bufs, frame->n_vectors); + /* set the initial values for the current buffer the next pointers */ + b = bufs; + next = nexts; + + n_left = frame->n_vectors; + while (n_left > 0) + { + u32 next_index = 0; + u32 sw_if_index0 = + vnet_buffer (b[0])->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; + u16 ethertype = 0; + + int error0 = 0; + + ethernet_header_t *h0 = vlib_buffer_get_current (b[0]); + u8 *l3h0 = (u8 *) h0 + vnet_buffer (b[0])->l2.l2_len; + ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2)); + + if (is_permitted_ethertype (am, sw_if_index0, is_output, ethertype)) + vnet_feature_next (&next_index, b[0]); + + next[0] = next_index; + + if (0 == next[0]) + b[0]->error = error_node->errors[error0]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b[0]->flags & VLIB_BUFFER_IS_TRACED))) + { + nonip_in_out_trace_t *t = + vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->ethertype = ethertype; + t->next_index = next[0]; + } + next[0] = next[0] < node->n_next_nodes ? next[0] : 0; + + next++; + b++; + n_left--; + } + vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); + + return frame->n_vectors; +} + +vlib_node_registration_t acl_in_nonip_node; +VLIB_NODE_FN (acl_in_nonip_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return nonip_in_out_node_fn (vm, node, frame, 0, &acl_in_nonip_node); +} + +vlib_node_registration_t acl_out_nonip_node; +VLIB_NODE_FN (acl_out_nonip_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return nonip_in_out_node_fn (vm, node, frame, 1, &acl_in_nonip_node); +} + + +/* *INDENT-OFF* */ + +VLIB_NODE_FUNCTION_MULTIARCH (acl_in_nonip_node, acl_in_nonip_node_fn) +VLIB_NODE_FUNCTION_MULTIARCH (acl_out_nonip_node, acl_out_nonip_node_fn) + +VLIB_REGISTER_NODE (acl_in_nonip_node) = +{ + .name = "acl-plugin-in-nonip-l2", + .vector_size = sizeof (u32), + .format_trace = format_l2_nonip_in_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (fa_in_nonip_error_strings), + .error_strings = fa_in_nonip_error_strings, + .n_next_nodes = ACL_FA_N_NEXT, + .next_nodes = + { + [ACL_FA_ERROR_DROP] = "error-drop", + } +}; + +VNET_FEATURE_INIT (acl_in_l2_nonip_fa_feature, static) = +{ + .arc_name = "l2-input-nonip", + .node_name = "acl-plugin-in-nonip-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; + +VLIB_REGISTER_NODE (acl_out_nonip_node) = +{ + .name = "acl-plugin-out-nonip-l2", + .vector_size = sizeof (u32), + .format_trace = format_l2_nonip_out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (fa_out_nonip_error_strings), + .error_strings = fa_out_nonip_error_strings, + .n_next_nodes = ACL_FA_N_NEXT, + .next_nodes = + { + [ACL_FA_ERROR_DROP] = "error-drop", + } +}; + +VNET_FEATURE_INIT (acl_out_l2_nonip_fa_feature, static) = +{ + .arc_name = "l2-output-nonip", + .node_name = "acl-plugin-out-nonip-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + +/* *INDENT-ON* */ + + + always_inline u16 get_current_policy_epoch (acl_main_t * am, int is_input, u32 sw_if_index0) { @@ -82,7 +308,7 @@ get_current_policy_epoch (acl_main_t * am, int is_input, u32 sw_if_index0) always_inline uword acl_fa_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, int is_ip6, - int is_input, int is_l2_path, u32 * l2_feat_next_node_index, + int is_input, int is_l2_path, vlib_node_registration_t * acl_fa_node) { u32 n_left, *from; @@ -278,10 +504,7 @@ acl_fa_node_fn (vlib_main_t * vm, if (action > 0) { - if (is_l2_path) - next0 = vnet_l2_feature_next (b[0], l2_feat_next_node_index, 0); - else - vnet_feature_next (&next0, b[0]); + vnet_feature_next (&next0, b[0]); } #ifdef FA_NODE_VERBOSE_DEBUG clib_warning @@ -342,10 +565,7 @@ VLIB_NODE_FN (acl_in_l2_ip6_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 1, 1, 1, - am->fa_acl_in_ip6_l2_node_feat_next_node_index, - &acl_in_l2_ip6_node); + return acl_fa_node_fn (vm, node, frame, 1, 1, 1, &acl_in_l2_ip6_node); } vlib_node_registration_t acl_in_l2_ip4_node; @@ -353,10 +573,7 @@ VLIB_NODE_FN (acl_in_l2_ip4_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 0, 1, 1, - am->fa_acl_in_ip4_l2_node_feat_next_node_index, - &acl_in_l2_ip4_node); + return acl_fa_node_fn (vm, node, frame, 0, 1, 1, &acl_in_l2_ip4_node); } vlib_node_registration_t acl_out_l2_ip6_node; @@ -364,10 +581,7 @@ VLIB_NODE_FN (acl_out_l2_ip6_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 1, 0, 1, - am->fa_acl_out_ip6_l2_node_feat_next_node_index, - &acl_out_l2_ip6_node); + return acl_fa_node_fn (vm, node, frame, 1, 0, 1, &acl_out_l2_ip6_node); } vlib_node_registration_t acl_out_l2_ip4_node; @@ -375,10 +589,7 @@ VLIB_NODE_FN (acl_out_l2_ip4_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 0, 0, 1, - am->fa_acl_out_ip4_l2_node_feat_next_node_index, - &acl_out_l2_ip4_node); + return acl_fa_node_fn (vm, node, frame, 0, 0, 1, &acl_out_l2_ip4_node); } /**** L3 processing path nodes ****/ @@ -388,7 +599,7 @@ VLIB_NODE_FN (acl_in_fa_ip6_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return acl_fa_node_fn (vm, node, frame, 1, 1, 0, 0, &acl_in_fa_ip6_node); + return acl_fa_node_fn (vm, node, frame, 1, 1, 0, &acl_in_fa_ip6_node); } vlib_node_registration_t acl_in_fa_ip4_node; @@ -396,7 +607,7 @@ VLIB_NODE_FN (acl_in_fa_ip4_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return acl_fa_node_fn (vm, node, frame, 0, 1, 0, 0, &acl_in_fa_ip4_node); + return acl_fa_node_fn (vm, node, frame, 0, 1, 0, &acl_in_fa_ip4_node); } vlib_node_registration_t acl_out_fa_ip6_node; @@ -404,7 +615,7 @@ VLIB_NODE_FN (acl_out_fa_ip6_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return acl_fa_node_fn (vm, node, frame, 1, 0, 0, 0, &acl_out_fa_ip6_node); + return acl_fa_node_fn (vm, node, frame, 1, 0, 0, &acl_out_fa_ip6_node); } vlib_node_registration_t acl_out_fa_ip4_node; @@ -412,7 +623,7 @@ VLIB_NODE_FN (acl_out_fa_ip4_node) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return acl_fa_node_fn (vm, node, frame, 0, 0, 0, 0, &acl_out_fa_ip4_node); + return acl_fa_node_fn (vm, node, frame, 0, 0, 0, &acl_out_fa_ip4_node); } static u8 * @@ -499,6 +710,13 @@ VLIB_REGISTER_NODE (acl_in_l2_ip6_node) = } }; +VNET_FEATURE_INIT (acl_in_l2_ip6_fa_feature, static) = +{ + .arc_name = "l2-input-ip6", + .node_name = "acl-plugin-in-ip6-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; + VLIB_REGISTER_NODE (acl_in_l2_ip4_node) = { .name = "acl-plugin-in-ip4-l2", @@ -514,6 +732,14 @@ VLIB_REGISTER_NODE (acl_in_l2_ip4_node) = } }; +VNET_FEATURE_INIT (acl_in_l2_ip4_fa_feature, static) = +{ + .arc_name = "l2-input-ip4", + .node_name = "acl-plugin-in-ip4-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; + + VLIB_REGISTER_NODE (acl_out_l2_ip6_node) = { .name = "acl-plugin-out-ip6-l2", @@ -529,6 +755,14 @@ VLIB_REGISTER_NODE (acl_out_l2_ip6_node) = } }; +VNET_FEATURE_INIT (acl_out_l2_ip6_fa_feature, static) = +{ + .arc_name = "l2-output-ip6", + .node_name = "acl-plugin-out-ip6-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + + VLIB_REGISTER_NODE (acl_out_l2_ip4_node) = { .name = "acl-plugin-out-ip4-l2", @@ -544,6 +778,13 @@ VLIB_REGISTER_NODE (acl_out_l2_ip4_node) = } }; +VNET_FEATURE_INIT (acl_out_l2_ip4_fa_feature, static) = +{ + .arc_name = "l2-output-ip4", + .node_name = "acl-plugin-out-ip4-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + VLIB_REGISTER_NODE (acl_in_fa_ip6_node) = { diff --git a/test/test_acl_plugin.py b/test/test_acl_plugin.py index fd45b4a27e7..5ccfa39e525 100644 --- a/test/test_acl_plugin.py +++ b/test/test_acl_plugin.py @@ -154,6 +154,14 @@ class TestACLplugin(VppTestCase): """ super(TestACLplugin, self).tearDown() if not self.vpp_dead: + cli = "show vlib graph l2-input-feat-arc" + self.logger.info(self.vapi.ppcli(cli)) + cli = "show vlib graph l2-input-feat-arc-end" + self.logger.info(self.vapi.ppcli(cli)) + cli = "show vlib graph l2-output-feat-arc" + self.logger.info(self.vapi.ppcli(cli)) + cli = "show vlib graph l2-output-feat-arc-end" + self.logger.info(self.vapi.ppcli(cli)) self.logger.info(self.vapi.ppcli("show l2fib verbose")) self.logger.info(self.vapi.ppcli("show acl-plugin acl")) self.logger.info(self.vapi.ppcli("show acl-plugin interface")) -- cgit 1.2.3-korg