diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/acl/acl.api | 20 | ||||
-rw-r--r-- | src/plugins/acl/acl.c | 203 | ||||
-rw-r--r-- | src/plugins/acl/acl.h | 6 | ||||
-rw-r--r-- | src/plugins/acl/acl_test.c | 60 | ||||
-rw-r--r-- | src/plugins/acl/manual_fns.h | 24 |
5 files changed, 308 insertions, 5 deletions
diff --git a/src/plugins/acl/acl.api b/src/plugins/acl/acl.api index e3166d691a8..047fc683b87 100644 --- a/src/plugins/acl/acl.api +++ b/src/plugins/acl/acl.api @@ -476,3 +476,23 @@ define macip_acl_interface_list_details u8 count; u32 acls[count]; }; + +/** \brief Set the ethertype whitelists on an interface. Takes effect when applying ACLs on the interface, so must be given prior. + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface to alter the list of ACLs on + @param count - total number of whitelisted ethertypes in the vector + @param n_input - this many first elements correspond to input whitelisted ethertypes, the rest - output + @param whitelist - vector of whitelisted ethertypes +*/ + +autoreply manual_print define acl_interface_set_etype_whitelist +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u8 count; /* Total number of ethertypes in the whitelist */ + u8 n_input; /* first n_input ethertypes are input, the rest - output */ + u16 whitelist[count]; +}; + diff --git a/src/plugins/acl/acl.c b/src/plugins/acl/acl.c index 82e1ab04e84..82a5670235b 100644 --- a/src/plugins/acl/acl.c +++ b/src/plugins/acl/acl.c @@ -75,7 +75,8 @@ _(MACIP_ACL_DEL, macip_acl_del) \ _(MACIP_ACL_INTERFACE_ADD_DEL, macip_acl_interface_add_del) \ _(MACIP_ACL_DUMP, macip_acl_dump) \ _(MACIP_ACL_INTERFACE_GET, macip_acl_interface_get) \ -_(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump) +_(MACIP_ACL_INTERFACE_LIST_DUMP, macip_acl_interface_list_dump) \ +_(ACL_INTERFACE_SET_ETYPE_WHITELIST, acl_interface_set_etype_whitelist) /* *INDENT-OFF* */ @@ -85,6 +86,24 @@ VLIB_PLUGIN_REGISTER () = { }; /* *INDENT-ON* */ +/* Format vec16. */ +u8 * +format_vec16 (u8 * s, va_list * va) +{ + u16 *v = va_arg (*va, u16 *); + char *fmt = va_arg (*va, char *); + uword i; + for (i = 0; i < vec_len (v); i++) + { + if (i > 0) + s = format (s, ", "); + s = format (s, fmt, v[i]); + } + return s; +} + + + static void * acl_set_heap (acl_main_t * am) @@ -402,6 +421,10 @@ u8 ip4_5tuple_mask[] = _(padpad) __ __ __ __ _(padeth) __ __; + u8 ethertype_mask[] = + _(" dmac smac etype ") + _(ether) __ __ __ __ __ __ v __ __ __ __ __ __ v XX XX __ __; + /* *INDENT-ON* */ #undef XX #undef __ @@ -486,6 +509,7 @@ acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index) 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, @@ -496,6 +520,8 @@ acl_unhook_l2_input_classify (acl_main_t * am, u32 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); @@ -539,6 +565,15 @@ acl_unhook_l2_input_classify (acl_main_t * am, u32 sw_if_index) 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; } @@ -551,6 +586,7 @@ acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index) 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, @@ -561,6 +597,8 @@ acl_unhook_l2_output_classify (acl_main_t * am, u32 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); @@ -605,6 +643,15 @@ acl_unhook_l2_output_classify (acl_main_t * am, u32 sw_if_index) 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; } @@ -677,6 +724,45 @@ acl_add_vlan_session (acl_main_t * am, u32 table_index, u8 is_output, } 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; @@ -684,6 +770,7 @@ acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index) 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); @@ -712,10 +799,18 @@ acl_hook_l2_input_classify (acl_main_t * am, u32 sw_if_index) 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, ~0, - ~0, &dot1ad_table_index, 1); + 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, @@ -774,6 +869,10 @@ acl_hook_l2_input_classify (acl_main_t * am, u32 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: @@ -789,6 +888,7 @@ acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index) 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); @@ -816,10 +916,19 @@ acl_hook_l2_output_classify (acl_main_t * am, u32 sw_if_index) 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, ~0, - ~0, &dot1ad_table_index, 1); + 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, @@ -881,6 +990,8 @@ acl_hook_l2_output_classify (acl_main_t * am, u32 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: @@ -1187,6 +1298,43 @@ acl_interface_add_del_inout_acl (u32 sw_if_index, u8 is_add, u8 is_input, return rv; } +static int +acl_set_etype_whitelists (acl_main_t * am, u32 sw_if_index, u16 * vec_in, + u16 * vec_out) +{ + vec_validate (am->input_etype_whitelist_by_sw_if_index, sw_if_index); + vec_validate (am->output_etype_whitelist_by_sw_if_index, sw_if_index); + + vec_free (am->input_etype_whitelist_by_sw_if_index[sw_if_index]); + vec_free (am->output_etype_whitelist_by_sw_if_index[sw_if_index]); + + am->input_etype_whitelist_by_sw_if_index[sw_if_index] = vec_in; + am->output_etype_whitelist_by_sw_if_index[sw_if_index] = vec_out; + + /* + * if there are already inbound/outbound ACLs applied, toggle the + * enable/disable - this will recreate the necessary tables. + */ + + if (vec_len (am->input_acl_vec_by_sw_if_index) > sw_if_index) + { + if (vec_len (am->input_acl_vec_by_sw_if_index[sw_if_index]) > 0) + { + acl_interface_in_enable_disable (am, sw_if_index, 0); + acl_interface_in_enable_disable (am, sw_if_index, 1); + } + } + if (vec_len (am->output_acl_vec_by_sw_if_index) > sw_if_index) + { + if (vec_len (am->output_acl_vec_by_sw_if_index[sw_if_index]) > 0) + { + acl_interface_out_enable_disable (am, sw_if_index, 0); + acl_interface_out_enable_disable (am, sw_if_index, 1); + } + } + return 0; +} + typedef struct { @@ -2499,6 +2647,38 @@ static void } } +static void + vl_api_acl_interface_set_etype_whitelist_t_handler + (vl_api_acl_interface_set_etype_whitelist_t * mp) +{ + acl_main_t *am = &acl_main; + vl_api_acl_interface_set_etype_whitelist_reply_t *rmp; + int rv = 0; + int i; + vnet_interface_main_t *im = &am->vnet_main->interface_main; + u32 sw_if_index = ntohl (mp->sw_if_index); + u16 *vec_in = 0, *vec_out = 0; + void *oldheap = acl_set_heap (am); + + if (pool_is_free_index (im->sw_interfaces, sw_if_index)) + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + else + { + for (i = 0; i < mp->count; i++) + { + if (i < mp->n_input) + vec_add1 (vec_in, ntohs (mp->whitelist[i])); + else + vec_add1 (vec_out, ntohs (mp->whitelist[i])); + } + rv = acl_set_etype_whitelists (am, sw_if_index, vec_in, vec_out); + } + + clib_mem_set_heap (oldheap); + REPLY_MACRO (VL_API_ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY); +} + + /* Set up the API message handling tables */ static clib_error_t * acl_plugin_api_hookup (vlib_main_t * vm) @@ -3013,6 +3193,19 @@ acl_plugin_show_interface (acl_main_t * am, u32 sw_if_index, int show_acl) vlib_cli_output (vm, "sw_if_index %d:\n", swi); + if (intf_has_etype_whitelist (am, swi, 1)) + { + vlib_cli_output (vm, " input etype whitelist: %U", format_vec16, + am->input_etype_whitelist_by_sw_if_index[swi], + "%04x"); + } + if (intf_has_etype_whitelist (am, swi, 0)) + { + vlib_cli_output (vm, " output etype whitelist: %U", format_vec16, + am->output_etype_whitelist_by_sw_if_index[swi], + "%04x"); + } + if ((swi < vec_len (am->input_acl_vec_by_sw_if_index)) && (vec_len (am->input_acl_vec_by_sw_if_index[swi]) > 0)) { diff --git a/src/plugins/acl/acl.h b/src/plugins/acl/acl.h index 263867b61ff..07ed8681ef1 100644 --- a/src/plugins/acl/acl.h +++ b/src/plugins/acl/acl.h @@ -188,6 +188,12 @@ typedef struct { u32 *acl_dot1q_output_classify_table_by_sw_if_index; u32 *acl_dot1ad_output_classify_table_by_sw_if_index; + u32 *acl_etype_input_classify_table_by_sw_if_index; + u32 *acl_etype_output_classify_table_by_sw_if_index; + + u16 **input_etype_whitelist_by_sw_if_index; + u16 **output_etype_whitelist_by_sw_if_index; + /* MACIP (input) ACLs associated with the interfaces */ u32 *macip_acl_by_sw_if_index; diff --git a/src/plugins/acl/acl_test.c b/src/plugins/acl/acl_test.c index 90fd49980de..c264034c939 100644 --- a/src/plugins/acl/acl_test.c +++ b/src/plugins/acl/acl_test.c @@ -67,6 +67,7 @@ _(acl_del_reply) \ _(acl_interface_add_del_reply) \ _(macip_acl_interface_add_del_reply) \ _(acl_interface_set_acl_list_reply) \ +_(acl_interface_set_etype_whitelist_reply) \ _(macip_acl_del_reply) #define foreach_reply_retval_aclindex_handler \ @@ -269,6 +270,7 @@ _(ACL_ADD_REPLACE_REPLY, acl_add_replace_reply) \ _(ACL_DEL_REPLY, acl_del_reply) \ _(ACL_INTERFACE_ADD_DEL_REPLY, acl_interface_add_del_reply) \ _(ACL_INTERFACE_SET_ACL_LIST_REPLY, acl_interface_set_acl_list_reply) \ +_(ACL_INTERFACE_SET_ETYPE_WHITELIST_REPLY, acl_interface_set_etype_whitelist_reply) \ _(ACL_INTERFACE_LIST_DETAILS, acl_interface_list_details) \ _(ACL_DETAILS, acl_details) \ _(MACIP_ACL_ADD_REPLY, macip_acl_add_reply) \ @@ -746,6 +748,63 @@ static int api_acl_interface_set_acl_list (vat_main_t * vam) return ret; } +static int api_acl_interface_set_etype_whitelist (vat_main_t * vam) +{ + unformat_input_t * i = vam->input; + vl_api_acl_interface_set_etype_whitelist_t * mp; + u32 sw_if_index = ~0; + u32 ethertype = ~0; + u16 *etypes_in = 0; + u16 *etypes_out = 0; + u8 is_input = 1; + int ret; + +// acl_interface_set_etype_whitelist <intfc> | sw_if_index <if-idx> input [ethertype list] output [ethertype list] + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%x", ðertype)) + { + ethertype = ethertype & 0xffff; + if(is_input) + vec_add1(etypes_in, htons(ethertype)); + else + vec_add1(etypes_out, htons(ethertype)); + } + else if (unformat (i, "input")) + is_input = 1; + else if (unformat (i, "output")) + is_input = 0; + else + break; + } + + if (sw_if_index == ~0) { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + /* Construct the API message */ + M2(ACL_INTERFACE_SET_ETYPE_WHITELIST, mp, sizeof(u32) * (vec_len(etypes_in) + vec_len(etypes_out))); + mp->sw_if_index = ntohl(sw_if_index); + mp->n_input = vec_len(etypes_in); + mp->count = vec_len(etypes_in) + vec_len(etypes_out); + vec_append(etypes_in, etypes_out); + if (vec_len(etypes_in) > 0) + clib_memcpy(mp->whitelist, etypes_in, vec_len(etypes_in)*sizeof(etypes_in[0])); + + /* send it... */ + S(mp); + + /* Wait for a reply... */ + W (ret); + return ret; +} + static void api_acl_send_control_ping(vat_main_t *vam) { @@ -1163,6 +1222,7 @@ _(acl_del, "<acl-idx>") \ _(acl_dump, "[<acl-idx>]") \ _(acl_interface_add_del, "<intfc> | sw_if_index <if-idx> [add|del] [input|output] acl <acl-idx>") \ _(acl_interface_set_acl_list, "<intfc> | sw_if_index <if-idx> input [acl-idx list] output [acl-idx list]") \ +_(acl_interface_set_etype_whitelist, "<intfc> | sw_if_index <if-idx> input [ethertype list] output [ethertype list]") \ _(acl_interface_list_dump, "[<intfc> | sw_if_index <if-idx>]") \ _(macip_acl_add, "...") \ _(macip_acl_add_replace, "<acl-idx> [<ipv4|ipv6> <permit|deny|action N> [count <count>] [src] ip <ipaddress/[plen]> mac <mac> mask <mac_mask>, ... , ...") \ diff --git a/src/plugins/acl/manual_fns.h b/src/plugins/acl/manual_fns.h index e00f1abcc61..6ab014caf8d 100644 --- a/src/plugins/acl/manual_fns.h +++ b/src/plugins/acl/manual_fns.h @@ -360,6 +360,30 @@ vl_api_acl_interface_set_acl_list_t_print (vl_api_acl_interface_set_acl_list_t } static inline void * +vl_api_acl_interface_set_etype_whitelist_t_print (vl_api_acl_interface_set_etype_whitelist_t + * a, void *handle) +{ + u8 *s; + int i; + + s = format + (0, "SCRIPT: acl_interface_set_etype_whitelist sw_if_index %d count %d\n", + clib_net_to_host_u32 (a->sw_if_index), (u32) a->count); + + s = format (s, " input "); + + for (i = 0; i < a->count; i++) + { + if (i == a->n_input) + s = format (s, "output "); + s = format (s, "%x ", clib_net_to_host_u16 (a->whitelist[i])); + } + + PRINT_S; + return handle; +} + +static inline void * vl_api_acl_interface_add_del_t_print (vl_api_acl_interface_add_del_t * a, void *handle) { |