aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/acl/acl.c
diff options
context:
space:
mode:
authorAndrew Yourtchenko <ayourtch@gmail.com>2018-02-06 17:42:32 +0100
committerNeale Ranns <nranns@cisco.com>2018-02-08 15:51:46 +0000
commitc43b3f986476ffb4506b7115898e809a6e34f601 (patch)
tree63576d278689bfc0ebd6b15eb9178006151c33aa /src/plugins/acl/acl.c
parentbe2251b0c5b10a3a556e75c9bfbea96df4799297 (diff)
acl-plugin: add whitelisted ethertype mode (VPP-1163)
Currently, ACL plugin largely does not care about the ethertypes other than 0x0800 (IPv4) and 0x86dd (IPv6), the only exception being 0x0806 (ARP), which is dealt with by the MACIP ACLs. The other ethertypes in L2 mode are just let through. This adds a new API message acl_interface_set_etype_whitelist, which allows to flip the mode of a given interface into "ethertype whitelist mode": the caller of this message must supply the two lists (inbound and outbound) of the ethertypes that are to be permitted, the rest of the ethertypes are dropped. The whitelisting for a given interface and direction takes effect only when a policy ACL is also applied. This operates on the same classifier node as the one used for dispatching the policy ACL, thus, if one wishes for most of the reasonable IPv4 deployments to continue to operate within the whitelist mode, they must permit ARP ethertype (0x0806) The empty list for a given direction resets the processing to allow the unknown ethertypes. So, if one wants to just permit the IPv4 and IPv6 and nothing else, one can add their ethertypes to the whitelist. Add the "show acl-plugin interface" corresponding outputs about the whitelists, vat command, and unittests. Change-Id: I4659978c801f36d554b6615e56e424b77876662c Signed-off-by: Andrew Yourtchenko <ayourtch@gmail.com>
Diffstat (limited to 'src/plugins/acl/acl.c')
-rw-r--r--src/plugins/acl/acl.c203
1 files changed, 198 insertions, 5 deletions
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))
{