summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/acl/acl.api20
-rw-r--r--src/plugins/acl/acl.c203
-rw-r--r--src/plugins/acl/acl.h6
-rw-r--r--src/plugins/acl/acl_test.c60
-rw-r--r--src/plugins/acl/manual_fns.h24
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", &ethertype))
+ {
+ 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)
{