diff options
-rw-r--r-- | src/plugins/acl/acl.c | 2 | ||||
-rw-r--r-- | src/vat/api_format.c | 62 | ||||
-rw-r--r-- | src/vnet.am | 9 | ||||
-rw-r--r-- | src/vnet/classify/classify.api | 22 | ||||
-rw-r--r-- | src/vnet/classify/classify_api.c | 44 | ||||
-rw-r--r-- | src/vnet/classify/in_out_acl.c (renamed from src/vnet/classify/input_acl.c) | 188 | ||||
-rw-r--r-- | src/vnet/classify/in_out_acl.h (renamed from src/vnet/classify/input_acl.h) | 50 | ||||
-rw-r--r-- | src/vnet/classify/vnet_classify.c | 2 | ||||
-rw-r--r-- | src/vnet/classify/vnet_classify.h | 1 | ||||
-rw-r--r-- | src/vnet/ip/ip4_error.h | 3 | ||||
-rwxr-xr-x | src/vnet/ip/ip4_forward.c | 7 | ||||
-rw-r--r-- | src/vnet/ip/ip6_error.h | 3 | ||||
-rw-r--r-- | src/vnet/ip/ip6_forward.c | 6 | ||||
-rw-r--r-- | src/vnet/ip/ip_in_out_acl.c (renamed from src/vnet/ip/ip_input_acl.c) | 207 | ||||
-rw-r--r-- | src/vnet/ip/ip_init.c | 2 | ||||
-rw-r--r-- | src/vnet/l2/l2_in_out_acl.c (renamed from src/vnet/l2/l2_input_acl.c) | 180 | ||||
-rw-r--r-- | src/vnet/l2/l2_input.c | 3 | ||||
-rw-r--r-- | src/vnet/l2/l2_output_acl.c | 341 | ||||
-rw-r--r-- | src/vpp/api/custom_dump.c | 21 | ||||
-rw-r--r-- | test/test_classifier.py | 45 | ||||
-rw-r--r-- | test/vpp_papi_provider.py | 23 |
21 files changed, 719 insertions, 502 deletions
diff --git a/src/plugins/acl/acl.c b/src/plugins/acl/acl.c index 2a2aaa08d7e..8e1880a1d6b 100644 --- a/src/plugins/acl/acl.c +++ b/src/plugins/acl/acl.c @@ -20,7 +20,7 @@ #include <acl/acl.h> #include <vnet/l2/l2_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> #include <vpp/app/version.h> #include <vlibapi/api.h> diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 4f20ea82361..c133f6b6b9b 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -33,7 +33,7 @@ #include <vpp/api/vpe_msg_enum.h> #include <vnet/l2/l2_classify.h> #include <vnet/l2/l2_vtr.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> #include <vnet/classify/policer_classify.h> #include <vnet/classify/flow_classify.h> #include <vnet/mpls/mpls.h> @@ -5391,7 +5391,8 @@ _(tcp_configure_src_addresses_reply) \ _(dns_enable_disable_reply) \ _(dns_name_server_add_del_reply) \ _(session_rule_add_del_reply) \ -_(ip_container_proxy_add_del_reply) +_(ip_container_proxy_add_del_reply) \ +_(output_acl_set_interface_reply) #define _(n) \ static void vl_api_##n##_t_handler \ @@ -5719,6 +5720,7 @@ _(DNS_RESOLVE_IP_REPLY, dns_resolve_ip_reply) \ _(SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply) \ _(SESSION_RULES_DETAILS, session_rules_details) \ _(IP_CONTAINER_PROXY_ADD_DEL_REPLY, ip_container_proxy_add_del_reply) \ +_(OUTPUT_ACL_SET_INTERFACE_REPLY, output_acl_set_interface_reply) \ #define foreach_standalone_reply_msg \ _(SW_INTERFACE_EVENT, sw_interface_event) \ @@ -14139,6 +14141,59 @@ api_input_acl_set_interface (vat_main_t * vam) } static int +api_output_acl_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_output_acl_set_interface_t *mp; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 l2_table_index = ~0; + u8 is_add = 1; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "l2-table %d", &l2_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (OUTPUT_ACL_SET_INTERFACE, mp); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->l2_table_index = ntohl (l2_table_index); + mp->is_add = is_add; + + S (mp); + W (ret); + return ret; +} + +static int api_ip_address_dump (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -23113,6 +23168,9 @@ _(session_rule_add_del, "[add|del] proto <tcp/udp> <lcl-ip>/<plen> " \ "<lcl-port> <rmt-ip>/<plen> <rmt-port> action <nn>") \ _(session_rules_dump, "") \ _(ip_container_proxy_add_del, "[add|del] <address> <sw_if_index>") \ +_(output_acl_set_interface, \ + "<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>]\n" \ + " [l2-table <nn>] [del]") \ /* List of command functions, CLI names map directly to functions */ #define foreach_cli_function \ diff --git a/src/vnet.am b/src/vnet.am index 8f884748d0f..a5fb061c5d6 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -148,12 +148,11 @@ libvnet_la_SOURCES += \ vnet/l2/l2_fib.c \ vnet/l2/l2_flood.c \ vnet/l2/l2_fwd.c \ - vnet/l2/l2_input_acl.c \ vnet/l2/l2_input.c \ vnet/l2/l2_input_vtr.c \ vnet/l2/l2_learn.c \ - vnet/l2/l2_output_acl.c \ vnet/l2/l2_output.c \ + vnet/l2/l2_in_out_acl.c \ vnet/l2/l2_patch.c \ vnet/l2/l2_rw.c \ vnet/l2/l2_vtr.c \ @@ -307,7 +306,7 @@ API_FILES += vnet/lldp/lldp.api libvnet_la_SOURCES += \ vnet/classify/vnet_classify.c \ vnet/classify/ip_classify.c \ - vnet/classify/input_acl.c \ + vnet/classify/in_out_acl.c \ vnet/classify/policer_classify.c \ vnet/classify/flow_classify.c \ vnet/classify/flow_classify_node.c \ @@ -316,7 +315,7 @@ libvnet_la_SOURCES += \ nobase_include_HEADERS += \ vnet/classify/vnet_classify.h \ - vnet/classify/input_acl.h \ + vnet/classify/in_out_acl.h \ vnet/classify/policer_classify.h \ vnet/classify/flow_classify.h \ vnet/classify/classify.api.h @@ -357,7 +356,7 @@ libvnet_la_SOURCES += \ vnet/ip/ip_frag.c \ vnet/ip/ip.c \ vnet/ip/ip_init.c \ - vnet/ip/ip_input_acl.c \ + vnet/ip/ip_in_out_acl.c \ vnet/ip/lookup.c \ vnet/ip/ping.c \ vnet/ip/punt_api.c \ diff --git a/src/vnet/classify/classify.api b/src/vnet/classify/classify.api index c22d6104704..7320d5ffa90 100644 --- a/src/vnet/classify/classify.api +++ b/src/vnet/classify/classify.api @@ -384,6 +384,28 @@ autoreply define input_acl_set_interface u8 is_add; }; +/** \brief Set/unset output ACL interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface to set/unset output ACL + @param ip4_table_index - ip4 classify table index (~0 for skip) + @param ip6_table_index - ip6 classify table index (~0 for skip) + @param l2_table_index - l2 classify table index (~0 for skip) + @param is_add - Set output ACL if non-zero, else unset + Note: User is recommeneded to use just one valid table_index per call. + (ip4_table_index, ip6_table_index, or l2_table_index) +*/ +autoreply define output_acl_set_interface +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u32 ip4_table_index; + u32 ip6_table_index; + u32 l2_table_index; + u8 is_add; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/classify/classify_api.c b/src/vnet/classify/classify_api.c index 1893f6e7191..2cf79f3875d 100644 --- a/src/vnet/classify/classify_api.c +++ b/src/vnet/classify/classify_api.c @@ -24,7 +24,7 @@ #include <vnet/api_errno.h> #include <vnet/classify/vnet_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> #include <vnet/classify/policer_classify.h> #include <vnet/classify/flow_classify.h> #include <vnet/l2/l2_classify.h> @@ -60,7 +60,8 @@ _(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \ _(FLOW_CLASSIFY_DUMP, flow_classify_dump) \ _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ -_(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) +_(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ +_(OUTPUT_ACL_SET_INTERFACE, output_acl_set_interface) #define foreach_classify_add_del_table_field \ _(table_index) \ @@ -269,19 +270,21 @@ static void u32 sw_if_index = ntohl (mp->sw_if_index); u32 *acl = 0; - vec_validate (acl, INPUT_ACL_N_TABLES - 1); + vec_validate (acl, IN_OUT_ACL_N_TABLES - 1); vec_set (acl, ~0); VALIDATE_SW_IF_INDEX (mp); - input_acl_main_t *am = &input_acl_main; + in_out_acl_main_t *am = &in_out_acl_main; int if_idx; u32 type; - for (type = 0; type < INPUT_ACL_N_TABLES; type++) + for (type = 0; type < IN_OUT_ACL_N_TABLES; type++) { - u32 *vec_tbl = am->classify_table_index_by_sw_if_index[type]; + u32 *vec_tbl = + am->classify_table_index_by_sw_if_index[IN_OUT_ACL_INPUT_TABLE_GROUP] + [type]; if (vec_len (vec_tbl)) { for (if_idx = 0; if_idx < vec_len (vec_tbl); if_idx++) @@ -301,9 +304,9 @@ static void REPLY_MACRO2(VL_API_CLASSIFY_TABLE_BY_INTERFACE_REPLY, ({ rmp->sw_if_index = ntohl(sw_if_index); - rmp->l2_table_id = ntohl(acl[INPUT_ACL_TABLE_L2]); - rmp->ip4_table_id = ntohl(acl[INPUT_ACL_TABLE_IP4]); - rmp->ip6_table_id = ntohl(acl[INPUT_ACL_TABLE_IP6]); + rmp->l2_table_id = ntohl(acl[IN_OUT_ACL_TABLE_L2]); + rmp->ip4_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP4]); + rmp->ip6_table_id = ntohl(acl[IN_OUT_ACL_TABLE_IP6]); })); /* *INDENT-ON* */ vec_free (acl); @@ -585,6 +588,29 @@ static void vl_api_input_acl_set_interface_t_handler REPLY_MACRO (VL_API_INPUT_ACL_SET_INTERFACE_REPLY); } +static void vl_api_output_acl_set_interface_t_handler + (vl_api_output_acl_set_interface_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + vl_api_output_acl_set_interface_reply_t *rmp; + int rv; + + VALIDATE_SW_IF_INDEX (mp); + + u32 ip4_table_index = ntohl (mp->ip4_table_index); + u32 ip6_table_index = ntohl (mp->ip6_table_index); + u32 l2_table_index = ntohl (mp->l2_table_index); + u32 sw_if_index = ntohl (mp->sw_if_index); + + rv = vnet_set_output_acl_intfc (vm, sw_if_index, ip4_table_index, + ip6_table_index, l2_table_index, + mp->is_add); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_OUTPUT_ACL_SET_INTERFACE_REPLY); +} + /* * classify_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/classify/input_acl.c b/src/vnet/classify/in_out_acl.c index cf5053ef3ac..a34f6cec61a 100644 --- a/src/vnet/classify/input_acl.c +++ b/src/vnet/classify/in_out_acl.c @@ -14,62 +14,69 @@ */ #include <vnet/ip/ip.h> #include <vnet/classify/vnet_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> -input_acl_main_t input_acl_main; +in_out_acl_main_t in_out_acl_main; static int -vnet_inacl_ip_feature_enable (vlib_main_t * vnm, - input_acl_main_t * am, - u32 sw_if_index, - input_acl_table_id_t tid, int feature_enable) +vnet_in_out_acl_ip_feature_enable (vlib_main_t * vnm, + in_out_acl_main_t * am, + u32 sw_if_index, + in_out_acl_table_id_t tid, + int feature_enable, int is_output) { - if (tid == INPUT_ACL_TABLE_L2) + if (tid == IN_OUT_ACL_TABLE_L2) { - l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ACL, - feature_enable); + l2input_intf_bitmap_enable (sw_if_index, + is_output ? L2OUTPUT_FEAT_ACL : + L2INPUT_FEAT_ACL, feature_enable); } else { /* IP[46] */ vnet_feature_config_main_t *fcm; u8 arc; - if (tid == INPUT_ACL_TABLE_IP4) + if (tid == IN_OUT_ACL_TABLE_IP4) { - vnet_feature_enable_disable ("ip4-unicast", "ip4-inacl", + char *arc_name = is_output ? "ip4-output" : "ip4-unicast"; + vnet_feature_enable_disable (arc_name, + is_output ? "ip4-outacl" : "ip4-inacl", sw_if_index, feature_enable, 0, 0); - arc = vnet_get_feature_arc_index ("ip4-unicast"); + arc = vnet_get_feature_arc_index (arc_name); } else { - vnet_feature_enable_disable ("ip6-unicast", "ip6-inacl", + char *arc_name = is_output ? "ip6-output" : "ip6-unicast"; + vnet_feature_enable_disable (arc_name, + is_output ? "ip6-outacl" : "ip6-inacl", sw_if_index, feature_enable, 0, 0); - arc = vnet_get_feature_arc_index ("ip6-unicast"); + arc = vnet_get_feature_arc_index (arc_name); } fcm = vnet_get_feature_arc_config_main (arc); - am->vnet_config_main[tid] = &fcm->config_main; + am->vnet_config_main[is_output][tid] = &fcm->config_main; } return 0; } int -vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index, - u32 ip4_table_index, - u32 ip6_table_index, u32 l2_table_index, u32 is_add) +vnet_set_in_out_acl_intfc (vlib_main_t * vm, u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, u32 l2_table_index, + u32 is_add, u32 is_output) { - input_acl_main_t *am = &input_acl_main; + in_out_acl_main_t *am = &in_out_acl_main; vnet_classify_main_t *vcm = am->vnet_classify_main; - u32 acl[INPUT_ACL_N_TABLES] = { ip4_table_index, ip6_table_index, + u32 acl[IN_OUT_ACL_N_TABLES] = { ip4_table_index, ip6_table_index, l2_table_index }; u32 ti; /* Assume that we've validated sw_if_index in the API layer */ - for (ti = 0; ti < INPUT_ACL_N_TABLES; ti++) + for (ti = 0; ti < IN_OUT_ACL_N_TABLES; ti++) { if (acl[ti] == ~0) continue; @@ -78,12 +85,14 @@ vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index, return VNET_API_ERROR_NO_SUCH_TABLE; vec_validate_init_empty - (am->classify_table_index_by_sw_if_index[ti], sw_if_index, ~0); + (am->classify_table_index_by_sw_if_index[is_output][ti], sw_if_index, + ~0); /* Reject any DEL operation with wrong sw_if_index */ if (!is_add && (acl[ti] != - am->classify_table_index_by_sw_if_index[ti][sw_if_index])) + am->classify_table_index_by_sw_if_index[is_output][ti] + [sw_if_index])) { clib_warning ("Non-existent intf_idx=%d with table_index=%d for delete", @@ -93,23 +102,49 @@ vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index, /* Return ok on ADD operaton if feature is already enabled */ if (is_add && - am->classify_table_index_by_sw_if_index[ti][sw_if_index] != ~0) + am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] + != ~0) return 0; - vnet_inacl_ip_feature_enable (vm, am, sw_if_index, ti, is_add); + vnet_in_out_acl_ip_feature_enable (vm, am, sw_if_index, ti, is_add, + is_output); if (is_add) - am->classify_table_index_by_sw_if_index[ti][sw_if_index] = acl[ti]; + am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] = + acl[ti]; else - am->classify_table_index_by_sw_if_index[ti][sw_if_index] = ~0; + am->classify_table_index_by_sw_if_index[is_output][ti][sw_if_index] = + ~0; } return 0; } +int +vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, u32 l2_table_index, u32 is_add) +{ + return vnet_set_in_out_acl_intfc (vm, sw_if_index, ip4_table_index, + ip6_table_index, l2_table_index, is_add, + IN_OUT_ACL_INPUT_TABLE_GROUP); +} + +int +vnet_set_output_acl_intfc (vlib_main_t * vm, u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, u32 l2_table_index, + u32 is_add) +{ + return vnet_set_in_out_acl_intfc (vm, sw_if_index, ip4_table_index, + ip6_table_index, l2_table_index, is_add, + IN_OUT_ACL_OUTPUT_TABLE_GROUP); +} + static clib_error_t * -set_input_acl_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +set_in_out_acl_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd, + u32 is_output) { vnet_main_t *vnm = vnet_get_main (); u32 sw_if_index = ~0; @@ -146,8 +181,9 @@ set_input_acl_command_fn (vlib_main_t * vm, if (idx_cnt > 1) return clib_error_return (0, "Only one table index per API is allowed."); - rv = vnet_set_input_acl_intfc (vm, sw_if_index, ip4_table_index, - ip6_table_index, l2_table_index, is_add); + rv = vnet_set_in_out_acl_intfc (vm, sw_if_index, ip4_table_index, + ip6_table_index, l2_table_index, is_add, + is_output); switch (rv) { @@ -163,8 +199,24 @@ set_input_acl_command_fn (vlib_main_t * vm, return 0; } +static clib_error_t * +set_input_acl_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + return set_in_out_acl_command_fn (vm, input, cmd, + IN_OUT_ACL_INPUT_TABLE_GROUP); +} + +static clib_error_t * +set_output_acl_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + return set_in_out_acl_command_fn (vm, input, cmd, + IN_OUT_ACL_OUTPUT_TABLE_GROUP); +} + /* - * Configure interface to enable/disble input ACL feature: + * Configure interface to enable/disble input/output ACL features: * intfc - interface name to be configured as input ACL * Ip4-table <index> [del] - enable/disable IP4 input ACL * Ip6-table <index> [del] - enable/disable IP6 input ACL @@ -181,15 +233,22 @@ VLIB_CLI_COMMAND (set_input_acl_command, static) = { " [ip6-table <index>] [l2-table <index>] [del]", .function = set_input_acl_command_fn, }; +VLIB_CLI_COMMAND (set_output_acl_command, static) = { + .path = "set interface output acl", + .short_help = + "set interface output acl intfc <int> [ip4-table <index>]\n" + " [ip6-table <index>] [l2-table <index>] [del]", + .function = set_output_acl_command_fn, +}; /* *INDENT-ON* */ clib_error_t * -input_acl_init (vlib_main_t * vm) +in_out_acl_init (vlib_main_t * vm) { - input_acl_main_t *am = &input_acl_main; + in_out_acl_main_t *am = &in_out_acl_main; clib_error_t *error = 0; - if ((error = vlib_call_init_function (vm, ip_inacl_init))) + if ((error = vlib_call_init_function (vm, ip_in_out_acl_init))) return error; am->vlib_main = vm; @@ -199,22 +258,22 @@ input_acl_init (vlib_main_t * vm) return 0; } -VLIB_INIT_FUNCTION (input_acl_init); +VLIB_INIT_FUNCTION (in_out_acl_init); uword unformat_acl_type (unformat_input_t * input, va_list * args) { u32 *acl_type = va_arg (*args, u32 *); - u32 tid = INPUT_ACL_N_TABLES; + u32 tid = IN_OUT_ACL_N_TABLES; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "ip4")) - tid = INPUT_ACL_TABLE_IP4; + tid = IN_OUT_ACL_TABLE_IP4; else if (unformat (input, "ip6")) - tid = INPUT_ACL_TABLE_IP6; + tid = IN_OUT_ACL_TABLE_IP6; else if (unformat (input, "l2")) - tid = INPUT_ACL_TABLE_L2; + tid = IN_OUT_ACL_TABLE_L2; else break; } @@ -224,9 +283,9 @@ unformat_acl_type (unformat_input_t * input, va_list * args) } u8 * -format_vnet_inacl_info (u8 * s, va_list * va) +format_vnet_in_out_acl_info (u8 * s, va_list * va) { - input_acl_main_t *am = va_arg (*va, input_acl_main_t *); + in_out_acl_main_t *am = va_arg (*va, in_out_acl_main_t *); int sw_if_idx = va_arg (*va, int); u32 tid = va_arg (*va, u32); @@ -244,11 +303,12 @@ format_vnet_inacl_info (u8 * s, va_list * va) } static clib_error_t * -show_inacl_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +show_in_out_acl_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd, u32 is_output) { - input_acl_main_t *am = &input_acl_main; - u32 type = INPUT_ACL_N_TABLES; + in_out_acl_main_t *am = &in_out_acl_main; + u32 type = IN_OUT_ACL_N_TABLES; int i; u32 *vec_tbl; @@ -260,34 +320,58 @@ show_inacl_command_fn (vlib_main_t * vm, break; } - if (type == INPUT_ACL_N_TABLES) - return clib_error_return (0, "Invalid input ACL table type."); + if (type == IN_OUT_ACL_N_TABLES) + return clib_error_return (0, is_output ? "Invalid output ACL table type." + : "Invalid input ACL table type."); - vec_tbl = am->classify_table_index_by_sw_if_index[type]; + vec_tbl = am->classify_table_index_by_sw_if_index[is_output][type]; if (vec_len (vec_tbl)) - vlib_cli_output (vm, "%U", format_vnet_inacl_info, am, ~0 /* hdr */ , ~0); + vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info, am, ~0 /* hdr */ , + ~0); else - vlib_cli_output (vm, "No input ACL tables configured"); + vlib_cli_output (vm, is_output ? "No output ACL tables configured" + : "No input ACL tables configured"); for (i = 0; i < vec_len (vec_tbl); i++) { if (vec_elt (vec_tbl, i) == ~0) continue; - vlib_cli_output (vm, "%U", format_vnet_inacl_info, + vlib_cli_output (vm, "%U", format_vnet_in_out_acl_info, am, i, vec_elt (vec_tbl, i)); } return 0; } +static clib_error_t * +show_inacl_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + return show_in_out_acl_command_fn (vm, input, cmd, + IN_OUT_ACL_INPUT_TABLE_GROUP); +} + +static clib_error_t * +show_outacl_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + return show_in_out_acl_command_fn (vm, input, cmd, + IN_OUT_ACL_OUTPUT_TABLE_GROUP); +} + /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_inacl_command, static) = { .path = "show inacl", .short_help = "show inacl type [ip4|ip6|l2]", .function = show_inacl_command_fn, }; +VLIB_CLI_COMMAND (show_outacl_command, static) = { + .path = "show outacl", + .short_help = "show outacl type [ip4|ip6|l2]", + .function = show_outacl_command_fn, +}; /* *INDENT-ON* */ /* diff --git a/src/vnet/classify/input_acl.h b/src/vnet/classify/in_out_acl.h index a5f3bac6b99..be0323055d8 100644 --- a/src/vnet/classify/input_acl.h +++ b/src/vnet/classify/in_out_acl.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef __included_vnet_input_acl_h__ -#define __included_vnet_input_acl_h__ +#ifndef __included_vnet_in_out_acl_h__ +#define __included_vnet_in_out_acl_h__ #include <vlib/vlib.h> #include <vnet/vnet.h> @@ -22,39 +22,59 @@ typedef enum { - INPUT_ACL_TABLE_IP4, - INPUT_ACL_TABLE_IP6, - INPUT_ACL_TABLE_L2, - INPUT_ACL_N_TABLES, -} input_acl_table_id_t; - -typedef enum -{ ACL_NEXT_INDEX_DENY, ACL_NEXT_INDEX_N_NEXT, } acl_next_index_t; +typedef enum +{ + IN_OUT_ACL_TABLE_IP4, + IN_OUT_ACL_TABLE_IP6, + IN_OUT_ACL_TABLE_L2, + IN_OUT_ACL_N_TABLES, +} in_out_acl_table_id_t; + +typedef enum +{ + IN_OUT_ACL_INPUT_TABLE_GROUP, + IN_OUT_ACL_OUTPUT_TABLE_GROUP, + IN_OUT_ACL_N_TABLE_GROUPS +} in_out_acl_table_group_id_t; + typedef struct { /* classifier table vectors */ - u32 *classify_table_index_by_sw_if_index[INPUT_ACL_N_TABLES]; + u32 + * classify_table_index_by_sw_if_index[IN_OUT_ACL_N_TABLE_GROUPS] + [IN_OUT_ACL_N_TABLES]; /* convenience variables */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; vnet_classify_main_t *vnet_classify_main; - vnet_config_main_t *vnet_config_main[INPUT_ACL_N_TABLES]; -} input_acl_main_t; + vnet_config_main_t + * vnet_config_main[IN_OUT_ACL_N_TABLE_GROUPS][IN_OUT_ACL_N_TABLES]; +} in_out_acl_main_t; -extern input_acl_main_t input_acl_main; +extern in_out_acl_main_t in_out_acl_main; + +int vnet_set_in_out_acl_intfc (vlib_main_t * vm, u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, + u32 l2_table_index, u32 is_add, u32 is_output); int vnet_set_input_acl_intfc (vlib_main_t * vm, u32 sw_if_index, u32 ip4_table_index, u32 ip6_table_index, u32 l2_table_index, u32 is_add); -#endif /* __included_vnet_input_acl_h__ */ +int vnet_set_output_acl_intfc (vlib_main_t * vm, u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, + u32 l2_table_index, u32 is_add); + +#endif /* __included_vnet_in_out_acl_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c index ef45d1a4167..d287a2d39cf 100644 --- a/src/vnet/classify/vnet_classify.c +++ b/src/vnet/classify/vnet_classify.c @@ -13,7 +13,7 @@ * limitations under the License. */ #include <vnet/classify/vnet_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> #include <vnet/ip/ip.h> #include <vnet/api_errno.h> /* for API error numbers */ #include <vnet/l2/l2_classify.h> /* for L2_INPUT_CLASSIFY_NEXT_xxx */ diff --git a/src/vnet/classify/vnet_classify.h b/src/vnet/classify/vnet_classify.h index 40628015501..79e7f1a844e 100644 --- a/src/vnet/classify/vnet_classify.h +++ b/src/vnet/classify/vnet_classify.h @@ -27,6 +27,7 @@ #include <vnet/ip/ip6_packet.h> #include <vlib/cli.h> #include <vnet/l2/l2_input.h> +#include <vnet/l2/l2_output.h> #include <vnet/l2/feat_bitmap.h> #include <vnet/api_errno.h> /* for API error numbers */ diff --git a/src/vnet/ip/ip4_error.h b/src/vnet/ip/ip4_error.h index 00b1c6daad5..fa93e8673e5 100644 --- a/src/vnet/ip/ip4_error.h +++ b/src/vnet/ip/ip4_error.h @@ -76,6 +76,9 @@ /* Errors singalled by ip4-inacl */ \ _ (INACL_TABLE_MISS, "input ACL table-miss drops") \ _ (INACL_SESSION_DENY, "input ACL session deny drops") \ + /* Errors singalled by ip4-outacl */ \ + _ (OUTACL_TABLE_MISS, "output ACL table-miss drops") \ + _ (OUTACL_SESSION_DENY, "output ACL session deny drops") \ \ /* Erros from mfib-forward */ \ _ (RPF_FAILURE, "Multicast RPF check failed") \ diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 2a21135bb3e..a0f3a4bfae0 100755 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -1121,6 +1121,13 @@ VNET_FEATURE_INIT (ip4_source_and_port_range_check_tx, static) = { .arc_name = "ip4-output", .node_name = "ip4-source-and-port-range-check-tx", + .runs_before = VNET_FEATURES ("ip4-outacl"), +}; + +VNET_FEATURE_INIT (ip4_outacl, static) = +{ + .arc_name = "ip4-output", + .node_name = "ip4-outacl", .runs_before = VNET_FEATURES ("ipsec-output-ip4"), }; diff --git a/src/vnet/ip/ip6_error.h b/src/vnet/ip/ip6_error.h index 19f20625a10..cc5afb93102 100644 --- a/src/vnet/ip/ip6_error.h +++ b/src/vnet/ip/ip6_error.h @@ -72,6 +72,9 @@ /* Erros singalled by ip6-inacl */ \ _ (INACL_TABLE_MISS, "input ACL table-miss drops") \ _ (INACL_SESSION_DENY, "input ACL session deny drops") \ + /* Erros singalled by ip6-outacl */ \ + _ (OUTACL_TABLE_MISS, "output ACL table-miss drops") \ + _ (OUTACL_SESSION_DENY, "output ACL session deny drops") \ \ /* Errors signalled by ip6-reassembly */ \ _ (REASS_MISSING_UPPER, "missing-upper layer drops") \ diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 5b06ca7609d..fc71c3d2d97 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -670,6 +670,12 @@ VNET_FEATURE_ARC_INIT (ip6_output, static) = .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index, }; +VNET_FEATURE_INIT (ip6_outacl, static) = { + .arc_name = "ip6-output", + .node_name = "ip6-outacl", + .runs_before = VNET_FEATURES ("ipsec-output-ip6"), +}; + VNET_FEATURE_INIT (ip6_ipsec_output, static) = { .arc_name = "ip6-output", .node_name = "ipsec-output-ip6", diff --git a/src/vnet/ip/ip_input_acl.c b/src/vnet/ip/ip_in_out_acl.c index 3c54fe8be2c..b50f5b1ff67 100644 --- a/src/vnet/ip/ip_input_acl.c +++ b/src/vnet/ip/ip_in_out_acl.c @@ -14,7 +14,7 @@ */ #include <vnet/ip/ip.h> #include <vnet/classify/vnet_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> typedef struct { @@ -22,29 +22,49 @@ typedef struct u32 next_index; u32 table_index; u32 offset; -} ip_inacl_trace_t; +} ip_in_out_acl_trace_t; /* packet trace format function */ static u8 * -format_ip_inacl_trace (u8 * s, va_list * args) +format_ip_in_out_acl_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 *); - ip_inacl_trace_t *t = va_arg (*args, ip_inacl_trace_t *); + ip_in_out_acl_trace_t *t = va_arg (*args, ip_in_out_acl_trace_t *); - s = format (s, "INACL: sw_if_index %d, next_index %d, table %d, offset %d", + s = format (s, "%s: sw_if_index %d, next_index %d, table %d, offset %d", + is_output ? "OUTACL" : "INACL", t->sw_if_index, t->next_index, t->table_index, t->offset); return s; } +static u8 * +format_ip_inacl_trace (u8 * s, va_list * args) +{ + return format_ip_in_out_acl_trace (s, 0 /* is_output */ , args); +} + +static u8 * +format_ip_outacl_trace (u8 * s, va_list * args) +{ + return format_ip_in_out_acl_trace (s, 1 /* is_output */ , args); +} + vlib_node_registration_t ip4_inacl_node; +vlib_node_registration_t ip4_outacl_node; vlib_node_registration_t ip6_inacl_node; +vlib_node_registration_t ip6_outacl_node; #define foreach_ip_inacl_error \ _(MISS, "input ACL misses") \ _(HIT, "input ACL hits") \ _(CHAIN_HIT, "input ACL hits after chain walk") +#define foreach_ip_outacl_error \ +_(MISS, "output ACL misses") \ +_(HIT, "output ACL hits") \ +_(CHAIN_HIT, "output ACL hits after chain walk") + typedef enum { #define _(sym,str) IP_INACL_ERROR_##sym, @@ -59,19 +79,34 @@ static char *ip_inacl_error_strings[] = { #undef _ }; +typedef enum +{ +#define _(sym,str) IP_OUTACL_ERROR_##sym, + foreach_ip_outacl_error +#undef _ + IP_OUTACL_N_ERROR, +} ip_outacl_error_t; + +static char *ip_outacl_error_strings[] = { +#define _(sym,string) string, + foreach_ip_outacl_error +#undef _ +}; + static inline uword -ip_inacl_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame, int is_ip4) +ip_in_out_acl_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_ip4, int is_output) { u32 n_left_from, *from, *to_next; acl_next_index_t next_index; - input_acl_main_t *am = &input_acl_main; + in_out_acl_main_t *am = &in_out_acl_main; vnet_classify_main_t *vcm = am->vnet_classify_main; f64 now = vlib_time_now (vm); u32 hits = 0; u32 misses = 0; u32 chain_hits = 0; - input_acl_table_id_t tid; + in_out_acl_table_id_t tid; vlib_node_runtime_t *error_node; u32 n_next_nodes; @@ -79,12 +114,12 @@ ip_inacl_inline (vlib_main_t * vm, if (is_ip4) { - tid = INPUT_ACL_TABLE_IP4; + tid = IN_OUT_ACL_TABLE_IP4; error_node = vlib_node_get_runtime (vm, ip4_input_node.index); } else { - tid = INPUT_ACL_TABLE_IP6; + tid = IN_OUT_ACL_TABLE_IP6; error_node = vlib_node_get_runtime (vm, ip6_input_node.index); } @@ -121,13 +156,15 @@ ip_inacl_inline (vlib_main_t * vm, bi1 = from[1]; b1 = vlib_get_buffer (vm, bi1); - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index0 = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index0 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index0]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + sw_if_index1 = + vnet_buffer (b1)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index1 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index1]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index1]; t0 = pool_elt_at_index (vcm->tables, table_index0); @@ -138,6 +175,15 @@ ip_inacl_inline (vlib_main_t * vm, else h0 = b0->data; + if (is_output) + { + /* Save the rewrite length, since we are using the l2_classify struct */ + vnet_buffer (b0)->l2_classify.pad.l2_len = + vnet_buffer (b0)->ip.save_rewrite_length; + /* advance the match pointer so the matching happens on IP header */ + h0 += vnet_buffer (b0)->l2_classify.pad.l2_len; + } + vnet_buffer (b0)->l2_classify.hash = vnet_classify_hash_packet (t0, (u8 *) h0); @@ -148,6 +194,15 @@ ip_inacl_inline (vlib_main_t * vm, else h1 = b1->data; + if (is_output) + { + /* Save the rewrite length, since we are using the l2_classify struct */ + vnet_buffer (b1)->l2_classify.pad.l2_len = + vnet_buffer (b1)->ip.save_rewrite_length; + /* advance the match pointer so the matching happens on IP header */ + h1 += vnet_buffer (b1)->l2_classify.pad.l2_len; + } + vnet_buffer (b1)->l2_classify.hash = vnet_classify_hash_packet (t1, (u8 *) h1); @@ -173,9 +228,10 @@ ip_inacl_inline (vlib_main_t * vm, bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index0 = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index0 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index0]; t0 = pool_elt_at_index (vcm->tables, table_index0); @@ -184,6 +240,15 @@ ip_inacl_inline (vlib_main_t * vm, else h0 = b0->data; + if (is_output) + { + /* Save the rewrite length, since we are using the l2_classify struct */ + vnet_buffer (b0)->l2_classify.pad.l2_len = + vnet_buffer (b0)->ip.save_rewrite_length; + /* advance the match pointer so the matching happens on IP header */ + h0 += vnet_buffer (b0)->l2_classify.pad.l2_len; + } + vnet_buffer (b0)->l2_classify.hash = vnet_classify_hash_packet (t0, (u8 *) h0); @@ -235,6 +300,7 @@ ip_inacl_inline (vlib_main_t * vm, } } + /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; @@ -247,7 +313,7 @@ ip_inacl_inline (vlib_main_t * vm, table_index0 = vnet_buffer (b0)->l2_classify.table_index; e0 = 0; t0 = 0; - vnet_get_config_data (am->vnet_config_main[tid], + vnet_get_config_data (am->vnet_config_main[is_output][tid], &b0->current_config_index, &next0, /* # bytes of config data */ 0); @@ -265,6 +331,10 @@ ip_inacl_inline (vlib_main_t * vm, else h0 = b0->data; + /* advance the match pointer so the matching happens on IP header */ + if (is_output) + h0 += vnet_buffer (b0)->l2_classify.pad.l2_len; + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); if (e0) { @@ -279,17 +349,23 @@ ip_inacl_inline (vlib_main_t * vm, if (is_ip4) error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP4_ERROR_INACL_SESSION_DENY : IP4_ERROR_NONE; + (is_output ? IP4_ERROR_OUTACL_SESSION_DENY : + IP4_ERROR_INACL_SESSION_DENY) : IP4_ERROR_NONE; else error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP6_ERROR_INACL_SESSION_DENY : IP6_ERROR_NONE; + (is_output ? IP6_ERROR_OUTACL_SESSION_DENY : + IP6_ERROR_INACL_SESSION_DENY) : IP6_ERROR_NONE; b0->error = error_node->errors[error0]; - if (e0->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX || - e0->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX) - vnet_buffer (b0)->sw_if_index[VLIB_TX] = e0->metadata; - else if (e0->action == CLASSIFY_ACTION_SET_METADATA) - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = e0->metadata; + if (!is_output) + { + if (e0->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX || + e0->action == CLASSIFY_ACTION_SET_IP6_FIB_INDEX) + vnet_buffer (b0)->sw_if_index[VLIB_TX] = e0->metadata; + else if (e0->action == CLASSIFY_ACTION_SET_METADATA) + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = + e0->metadata; + } } else { @@ -307,10 +383,12 @@ ip_inacl_inline (vlib_main_t * vm, if (is_ip4) error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP4_ERROR_INACL_TABLE_MISS : IP4_ERROR_NONE; + (is_output ? IP4_ERROR_OUTACL_TABLE_MISS : + IP4_ERROR_INACL_TABLE_MISS) : IP4_ERROR_NONE; else error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP6_ERROR_INACL_TABLE_MISS : IP6_ERROR_NONE; + (is_output ? IP6_ERROR_OUTACL_TABLE_MISS : + IP6_ERROR_INACL_TABLE_MISS) : IP6_ERROR_NONE; b0->error = error_node->errors[error0]; break; } @@ -338,10 +416,12 @@ ip_inacl_inline (vlib_main_t * vm, if (is_ip4) error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP4_ERROR_INACL_SESSION_DENY : IP4_ERROR_NONE; + (is_output ? IP4_ERROR_OUTACL_SESSION_DENY : + IP4_ERROR_INACL_SESSION_DENY) : IP4_ERROR_NONE; else error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - IP6_ERROR_INACL_SESSION_DENY : IP6_ERROR_NONE; + (is_output ? IP6_ERROR_OUTACL_SESSION_DENY : + IP6_ERROR_INACL_SESSION_DENY) : IP6_ERROR_NONE; b0->error = error_node->errors[error0]; if (e0->action == CLASSIFY_ACTION_SET_IP4_FIB_INDEX @@ -358,14 +438,21 @@ ip_inacl_inline (vlib_main_t * vm, if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { - ip_inacl_trace_t *t = + ip_in_out_acl_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->sw_if_index = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; t->next_index = next0; t->table_index = t0 ? t0 - vcm->tables : ~0; t->offset = (e0 && t0) ? vnet_classify_get_offset (t0, e0) : ~0; } + if ((next0 == ACL_NEXT_INDEX_DENY) && is_output) + { + /* on output, for the drop node to work properly, go back to ip header */ + vlib_buffer_advance (b0, vnet_buffer (b0)->l2.l2_len); + } + /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, @@ -376,10 +463,13 @@ ip_inacl_inline (vlib_main_t * vm, } vlib_node_increment_counter (vm, node->node_index, + is_output ? IP_OUTACL_ERROR_MISS : IP_INACL_ERROR_MISS, misses); vlib_node_increment_counter (vm, node->node_index, + is_output ? IP_OUTACL_ERROR_HIT : IP_INACL_ERROR_HIT, hits); vlib_node_increment_counter (vm, node->node_index, + is_output ? IP_OUTACL_ERROR_CHAIN_HIT : IP_INACL_ERROR_CHAIN_HIT, chain_hits); return frame->n_vectors; } @@ -387,7 +477,16 @@ ip_inacl_inline (vlib_main_t * vm, static uword ip4_inacl (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip_inacl_inline (vm, node, frame, 1 /* is_ip4 */ ); + return ip_in_out_acl_inline (vm, node, frame, 1 /* is_ip4 */ , + 0 /* is_output */ ); +} + +static uword +ip4_outacl (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return ip_in_out_acl_inline (vm, node, frame, 1 /* is_ip4 */ , + 1 /* is_output */ ); } @@ -405,16 +504,39 @@ VLIB_REGISTER_NODE (ip4_inacl_node) = { [ACL_NEXT_INDEX_DENY] = "ip4-drop", }, }; + +VLIB_REGISTER_NODE (ip4_outacl_node) = { + .function = ip4_outacl, + .name = "ip4-outacl", + .vector_size = sizeof (u32), + .format_trace = format_ip_outacl_trace, + .n_errors = ARRAY_LEN(ip_outacl_error_strings), + .error_strings = ip_outacl_error_strings, + + .n_next_nodes = ACL_NEXT_INDEX_N_NEXT, + .next_nodes = { + [ACL_NEXT_INDEX_DENY] = "ip4-drop", + }, +}; /* *INDENT-ON* */ VLIB_NODE_FUNCTION_MULTIARCH (ip4_inacl_node, ip4_inacl); +VLIB_NODE_FUNCTION_MULTIARCH (ip4_outacl_node, ip4_outacl); static uword ip6_inacl (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ip_inacl_inline (vm, node, frame, 0 /* is_ip4 */ ); + return ip_in_out_acl_inline (vm, node, frame, 0 /* is_ip4 */ , + 0 /* is_output */ ); } +static uword +ip6_outacl (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return ip_in_out_acl_inline (vm, node, frame, 0 /* is_ip4 */ , + 1 /* is_output */ ); +} /* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_inacl_node) = { @@ -430,17 +552,32 @@ VLIB_REGISTER_NODE (ip6_inacl_node) = { [ACL_NEXT_INDEX_DENY] = "ip6-drop", }, }; + +VLIB_REGISTER_NODE (ip6_outacl_node) = { + .function = ip6_outacl, + .name = "ip6-outacl", + .vector_size = sizeof (u32), + .format_trace = format_ip_outacl_trace, + .n_errors = ARRAY_LEN(ip_outacl_error_strings), + .error_strings = ip_outacl_error_strings, + + .n_next_nodes = ACL_NEXT_INDEX_N_NEXT, + .next_nodes = { + [ACL_NEXT_INDEX_DENY] = "ip6-drop", + }, +}; /* *INDENT-ON* */ VLIB_NODE_FUNCTION_MULTIARCH (ip6_inacl_node, ip6_inacl); +VLIB_NODE_FUNCTION_MULTIARCH (ip6_outacl_node, ip6_outacl); static clib_error_t * -ip_inacl_init (vlib_main_t * vm) +ip_in_out_acl_init (vlib_main_t * vm) { return 0; } -VLIB_INIT_FUNCTION (ip_inacl_init); +VLIB_INIT_FUNCTION (ip_in_out_acl_init); /* diff --git a/src/vnet/ip/ip_init.c b/src/vnet/ip/ip_init.c index e181a4fdd9b..ddd66c2e817 100644 --- a/src/vnet/ip/ip_init.c +++ b/src/vnet/ip/ip_init.c @@ -128,7 +128,7 @@ do { \ if ((error = vlib_call_init_function (vm, ip_classify_init))) return error; - if ((error = vlib_call_init_function (vm, input_acl_init))) + if ((error = vlib_call_init_function (vm, in_out_acl_init))) return error; if ((error = vlib_call_init_function (vm, policer_classify_init))) diff --git a/src/vnet/l2/l2_input_acl.c b/src/vnet/l2/l2_in_out_acl.c index 84030888c04..6f86a9f66ae 100644 --- a/src/vnet/l2/l2_input_acl.c +++ b/src/vnet/l2/l2_in_out_acl.c @@ -1,7 +1,7 @@ /* - * l2_input_acl.c : layer 2 input acl processing + * l2_in_out_acl.c : layer 2 input/output acl processing * - * Copyright (c) 2013 Cisco and/or its affiliates. + * Copyright (c) 2013,2018 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -25,6 +25,7 @@ #include <vnet/ip/ip6_packet.h> #include <vlib/cli.h> #include <vnet/l2/l2_input.h> +#include <vnet/l2/l2_output.h> #include <vnet/l2/feat_bitmap.h> #include <vppinfra/error.h> @@ -32,18 +33,18 @@ #include <vppinfra/cache.h> #include <vnet/classify/vnet_classify.h> -#include <vnet/classify/input_acl.h> +#include <vnet/classify/in_out_acl.h> typedef struct { /* Next nodes for each feature */ - u32 feat_next_node_index[32]; + u32 feat_next_node_index[IN_OUT_ACL_N_TABLE_GROUPS][32]; /* convenience variables */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; -} l2_inacl_main_t; +} l2_in_out_acl_main_t; typedef struct { @@ -51,24 +52,38 @@ typedef struct u32 next_index; u32 table_index; u32 offset; -} l2_inacl_trace_t; +} l2_in_out_acl_trace_t; /* packet trace format function */ static u8 * -format_l2_inacl_trace (u8 * s, va_list * args) +format_l2_in_out_acl_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 *); - l2_inacl_trace_t *t = va_arg (*args, l2_inacl_trace_t *); + l2_in_out_acl_trace_t *t = va_arg (*args, l2_in_out_acl_trace_t *); - s = format (s, "INACL: sw_if_index %d, next_index %d, table %d, offset %d", + s = format (s, "%s: sw_if_index %d, next_index %d, table %d, offset %d", + is_output ? "OUTACL" : "INACL", t->sw_if_index, t->next_index, t->table_index, t->offset); return s; } -l2_inacl_main_t l2_inacl_main; +static u8 * +format_l2_inacl_trace (u8 * s, va_list * args) +{ + return format_l2_in_out_acl_trace (s, IN_OUT_ACL_INPUT_TABLE_GROUP, args); +} + +static u8 * +format_l2_outacl_trace (u8 * s, va_list * args) +{ + return format_l2_in_out_acl_trace (s, IN_OUT_ACL_OUTPUT_TABLE_GROUP, args); +} + +l2_in_out_acl_main_t l2_in_out_acl_main; static vlib_node_registration_t l2_inacl_node; +static vlib_node_registration_t l2_outacl_node; #define foreach_l2_inacl_error \ _(NONE, "valid input ACL packets") \ @@ -78,6 +93,14 @@ _(CHAIN_HIT, "input ACL hits after chain walk") \ _(TABLE_MISS, "input ACL table-miss drops") \ _(SESSION_DENY, "input ACL session deny drops") +#define foreach_l2_outacl_error \ +_(NONE, "valid output ACL packets") \ +_(MISS, "output ACL misses") \ +_(HIT, "output ACL hits") \ +_(CHAIN_HIT, "output ACL hits after chain walk") \ +_(TABLE_MISS, "output ACL table-miss drops") \ +_(SESSION_DENY, "output ACL session deny drops") + typedef enum { @@ -93,16 +116,32 @@ static char *l2_inacl_error_strings[] = { #undef _ }; -static uword -l2_inacl_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +typedef enum +{ +#define _(sym,str) L2_OUTACL_ERROR_##sym, + foreach_l2_outacl_error +#undef _ + L2_OUTACL_N_ERROR, +} l2_outacl_error_t; + +static char *l2_outacl_error_strings[] = { +#define _(sym,string) string, + foreach_l2_outacl_error +#undef _ +}; + + +static inline uword +l2_in_out_acl_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_output) { u32 n_left_from, *from, *to_next; acl_next_index_t next_index; - l2_inacl_main_t *msm = &l2_inacl_main; - input_acl_main_t *am = &input_acl_main; + l2_in_out_acl_main_t *msm = &l2_in_out_acl_main; + in_out_acl_main_t *am = &in_out_acl_main; vnet_classify_main_t *vcm = am->vnet_classify_main; - input_acl_table_id_t tid = INPUT_ACL_TABLE_L2; + in_out_acl_table_id_t tid = IN_OUT_ACL_TABLE_L2; f64 now = vlib_time_now (vm); u32 hits = 0; u32 misses = 0; @@ -141,13 +180,15 @@ l2_inacl_node_fn (vlib_main_t * vm, bi1 = from[1]; b1 = vlib_get_buffer (vm, bi1); - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index0 = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index0 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index0]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + sw_if_index1 = + vnet_buffer (b1)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index1 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index1]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index1]; t0 = pool_elt_at_index (vcm->tables, table_index0); @@ -193,9 +234,10 @@ l2_inacl_node_fn (vlib_main_t * vm, bi0 = from[0]; b0 = vlib_get_buffer (vm, bi0); - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index0 = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; table_index0 = - am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + am->classify_table_index_by_sw_if_index[is_output][tid][sw_if_index0]; t0 = pool_elt_at_index (vcm->tables, table_index0); @@ -272,8 +314,10 @@ l2_inacl_node_fn (vlib_main_t * vm, vnet_buffer (b0)->l2_classify.opaque_index = ~0; /* Determine the next node */ - next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index, - L2INPUT_FEAT_ACL); + next0 = + vnet_l2_feature_next (b0, msm->feat_next_node_index[is_output], + is_output ? L2OUTPUT_FEAT_ACL : + L2INPUT_FEAT_ACL); if (PREDICT_TRUE (table_index0 != ~0)) { @@ -299,8 +343,12 @@ l2_inacl_node_fn (vlib_main_t * vm, hits++; - error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - L2_INACL_ERROR_SESSION_DENY : L2_INACL_ERROR_NONE; + if (is_output) + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_OUTACL_ERROR_SESSION_DENY : L2_INACL_ERROR_NONE; + else + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_OUTACL_ERROR_SESSION_DENY : L2_OUTACL_ERROR_NONE; b0->error = node->errors[error0]; } else @@ -319,8 +367,13 @@ l2_inacl_node_fn (vlib_main_t * vm, misses++; - error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - L2_INACL_ERROR_TABLE_MISS : L2_INACL_ERROR_NONE; + if (is_output) + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_OUTACL_ERROR_TABLE_MISS : + L2_OUTACL_ERROR_NONE; + else + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_INACL_ERROR_TABLE_MISS : L2_INACL_ERROR_NONE; b0->error = node->errors[error0]; break; } @@ -344,8 +397,14 @@ l2_inacl_node_fn (vlib_main_t * vm, hits++; chain_hits++; - error0 = (next0 == ACL_NEXT_INDEX_DENY) ? - L2_INACL_ERROR_SESSION_DENY : L2_INACL_ERROR_NONE; + if (is_output) + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_OUTACL_ERROR_SESSION_DENY : + L2_OUTACL_ERROR_NONE; + else + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_INACL_ERROR_SESSION_DENY : + L2_INACL_ERROR_NONE; b0->error = node->errors[error0]; break; } @@ -356,9 +415,10 @@ l2_inacl_node_fn (vlib_main_t * vm, if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { - l2_inacl_trace_t *t = + l2_in_out_acl_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->sw_if_index = + vnet_buffer (b0)->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; t->next_index = next0; t->table_index = t0 ? t0 - vcm->tables : ~0; t->offset = (t0 && e0) ? vnet_classify_get_offset (t0, e0) : ~0; @@ -374,14 +434,33 @@ l2_inacl_node_fn (vlib_main_t * vm, } vlib_node_increment_counter (vm, node->node_index, + is_output ? L2_OUTACL_ERROR_MISS : L2_INACL_ERROR_MISS, misses); vlib_node_increment_counter (vm, node->node_index, + is_output ? L2_OUTACL_ERROR_HIT : L2_INACL_ERROR_HIT, hits); vlib_node_increment_counter (vm, node->node_index, + is_output ? L2_OUTACL_ERROR_CHAIN_HIT : L2_INACL_ERROR_CHAIN_HIT, chain_hits); return frame->n_vectors; } +static uword +l2_inacl_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return l2_in_out_acl_node_fn (vm, node, frame, + IN_OUT_ACL_INPUT_TABLE_GROUP); +} + +static uword +l2_outacl_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return l2_in_out_acl_node_fn (vm, node, frame, + IN_OUT_ACL_OUTPUT_TABLE_GROUP); +} + /* *INDENT-OFF* */ VLIB_REGISTER_NODE (l2_inacl_node,static) = { .function = l2_inacl_node_fn, @@ -400,12 +479,34 @@ VLIB_REGISTER_NODE (l2_inacl_node,static) = { [ACL_NEXT_INDEX_DENY] = "error-drop", }, }; -/* *INDENT-ON* */ + +VLIB_REGISTER_NODE (l2_outacl_node,static) = { + .function = l2_outacl_node_fn, + .name = "l2-output-acl", + .vector_size = sizeof (u32), + .format_trace = format_l2_outacl_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_outacl_error_strings), + .error_strings = l2_outacl_error_strings, + + .n_next_nodes = ACL_NEXT_INDEX_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [ACL_NEXT_INDEX_DENY] = "error-drop", + }, +}; VLIB_NODE_FUNCTION_MULTIARCH (l2_inacl_node, l2_inacl_node_fn) - clib_error_t *l2_inacl_init (vlib_main_t * vm) +VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn) +/* *INDENT-ON* */ + + +clib_error_t * +l2_in_out_acl_init (vlib_main_t * vm) { - l2_inacl_main_t *mp = &l2_inacl_main; + l2_in_out_acl_main_t *mp = &l2_in_out_acl_main; mp->vlib_main = vm; mp->vnet_main = vnet_get_main (); @@ -415,12 +516,17 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_inacl_node, l2_inacl_node_fn) l2_inacl_node.index, L2INPUT_N_FEAT, l2input_get_feat_names (), - mp->feat_next_node_index); + mp->feat_next_node_index + [IN_OUT_ACL_INPUT_TABLE_GROUP]); + feat_bitmap_init_next_nodes (vm, l2_outacl_node.index, L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + mp->feat_next_node_index + [IN_OUT_ACL_OUTPUT_TABLE_GROUP]); return 0; } -VLIB_INIT_FUNCTION (l2_inacl_init); +VLIB_INIT_FUNCTION (l2_in_out_acl_init); /* * fd.io coding-style-patch-verification: ON diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 591211e9805..c05f5cfcd2c 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -1148,14 +1148,13 @@ _(l2fib_init) \ _(l2_input_classify_init) \ _(l2bd_init) \ _(l2fwd_init) \ -_(l2_inacl_init) \ +_(l2_in_out_acl_init) \ _(l2input_init) \ _(l2_vtr_init) \ _(l2_invtr_init) \ _(l2_efp_filter_init) \ _(l2learn_init) \ _(l2flood_init) \ -_(l2_outacl_init) \ _(l2output_init) \ _(l2_patch_init) \ _(l2_xcrw_init) diff --git a/src/vnet/l2/l2_output_acl.c b/src/vnet/l2/l2_output_acl.c deleted file mode 100644 index 7d051326ee0..00000000000 --- a/src/vnet/l2/l2_output_acl.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * l2_output_acl.c : layer 2 output acl processing - * - * Copyright (c) 2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <vlib/vlib.h> -#include <vnet/vnet.h> -#include <vnet/pg/pg.h> -#include <vnet/ethernet/ethernet.h> -#include <vnet/ethernet/packet.h> -#include <vnet/ip/ip_packet.h> -#include <vnet/ip/ip4_packet.h> -#include <vnet/ip/ip6_packet.h> -#include <vlib/cli.h> -#include <vnet/l2/feat_bitmap.h> -#include <vnet/l2/l2_output.h> - -#include <vppinfra/error.h> -#include <vppinfra/hash.h> -#include <vppinfra/cache.h> - - -typedef struct -{ - /* Next nodes for L2 output features */ - u32 l2_out_feat_next[32]; - - /* convenience variables */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} l2_outacl_main_t; - - - -typedef struct -{ - /* per-pkt trace data */ - u8 src[6]; - u8 dst[6]; - u32 next_index; - u32 sw_if_index; -} l2_outacl_trace_t; - -/* packet trace format function */ -static u8 * -format_l2_outacl_trace (u8 * s, 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 *); - l2_outacl_trace_t *t = va_arg (*args, l2_outacl_trace_t *); - - s = format (s, "l2-output-acl: sw_if_index %d dst %U src %U", - t->sw_if_index, - format_ethernet_address, t->dst, - format_ethernet_address, t->src); - return s; -} - -l2_outacl_main_t l2_outacl_main; - -static vlib_node_registration_t l2_outacl_node; - -#define foreach_l2_outacl_error \ -_(L2_OUTACL, "L2 output ACL packets") \ -_(DROP, "L2 output drops") - -typedef enum -{ -#define _(sym,str) L2_OUTACL_ERROR_##sym, - foreach_l2_outacl_error -#undef _ - L2_OUTACL_N_ERROR, -} l2_outacl_error_t; - -static char *l2_outacl_error_strings[] = { -#define _(sym,string) string, - foreach_l2_outacl_error -#undef _ -}; - -typedef enum -{ - L2_OUTACL_NEXT_DROP, - L2_OUTACL_N_NEXT, -} l2_outacl_next_t; - - - -static uword -l2_outacl_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - l2_outacl_next_t next_index; - l2_outacl_main_t *msm = &l2_outacl_main; - vlib_node_t *n = vlib_get_node (vm, l2_outacl_node.index); - u32 node_counter_base_index = n->error_heap_index; - vlib_error_main_t *em = &vm->error_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; /* number of packets to process */ - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - /* get space to enqueue frame to graph node "next_index" */ - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (0 && n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - u32 next0, next1; - u32 sw_if_index0, sw_if_index1; - ethernet_header_t *h0, *h1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - /* bi is "buffer index", b is pointer to the buffer */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - /* TX interface handles */ - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - l2_outacl_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - clib_memcpy (t->src, h0->src_address, 6); - clib_memcpy (t->dst, h0->dst_address, 6); - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - l2_outacl_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - t->next_index = next1; - clib_memcpy (t->src, h1->src_address, 6); - clib_memcpy (t->dst, h1->dst_address, 6); - } - } - - em->counters[node_counter_base_index + L2_OUTACL_ERROR_L2_OUTACL] += - 2; - - /* add core loop code here */ - - /* verify speculative enqueues, maybe switch current next frame */ - /* if next0==next1==next_index then nothing special needs to be done */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0; - u32 sw_if_index0; - ethernet_header_t *h0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - h0 = vlib_buffer_get_current (b0); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - l2_outacl_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - clib_memcpy (t->src, h0->src_address, 6); - clib_memcpy (t->dst, h0->dst_address, 6); - } - - em->counters[node_counter_base_index + L2_OUTACL_ERROR_L2_OUTACL] += - 1; - - /* - * L2_OUTACL code - * Dummy for now, just go to next feature node - */ - - /* Determine next node */ - next0 = vnet_l2_feature_next (b0, msm->l2_out_feat_next, - L2OUTPUT_FEAT_ACL); - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (l2_outacl_node,static) = { - .function = l2_outacl_node_fn, - .name = "l2-output-acl", - .vector_size = sizeof (u32), - .format_trace = format_l2_outacl_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(l2_outacl_error_strings), - .error_strings = l2_outacl_error_strings, - - .n_next_nodes = L2_OUTACL_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [L2_OUTACL_NEXT_DROP] = "error-drop", - }, -}; -/* *INDENT-ON* */ - -VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn) - clib_error_t *l2_outacl_init (vlib_main_t * vm) -{ - l2_outacl_main_t *mp = &l2_outacl_main; - - mp->vlib_main = vm; - mp->vnet_main = vnet_get_main (); - - /* Initialize the feature next-node indexes */ - feat_bitmap_init_next_nodes (vm, - l2_outacl_node.index, - L2OUTPUT_N_FEAT, - l2output_get_feat_names (), - mp->l2_out_feat_next); - - return 0; -} - -VLIB_INIT_FUNCTION (l2_outacl_init); - -#if 0 -/** @todo maybe someone will add output ACL's in the future. - * Set subinterface outacl enable/disable. - * The CLI format is: - * set interface acl output <interface> [disable] - */ -static clib_error_t * -int_l2_outacl (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - clib_error_t *error = 0; - u32 sw_if_index; - u32 enable; - - if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) - { - error = clib_error_return (0, "unknown interface `%U'", - format_unformat_error, input); - goto done; - } - - enable = 1; - if (unformat (input, "disable")) - { - enable = 0; - } - - /* set the interface flag */ - l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_ACL, enable); - -done: - return error; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (int_l2_outacl_cli, static) = { - .path = "set interface acl output", - .short_help = "set interface acl output <interface> [disable]", - .function = int_l2_outacl, -}; -/* *INDENT-ON* */ -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 62f3c5f4af5..5cd454e9566 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -1963,6 +1963,24 @@ static void *vl_api_input_acl_set_interface_t_print FINISH; } +static void *vl_api_output_acl_set_interface_t_print + (vl_api_output_acl_set_interface_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: output_acl_set_interface "); + + s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); + s = format (s, "ip4-table %d ", ntohl (mp->ip4_table_index)); + s = format (s, "ip6-table %d ", ntohl (mp->ip6_table_index)); + s = format (s, "l2-table %d ", ntohl (mp->l2_table_index)); + + if (mp->is_add == 0) + s = format (s, "del "); + + FINISH; +} + static void *vl_api_ip_address_dump_t_print (vl_api_ip_address_dump_t * mp, void *handle) { @@ -3491,7 +3509,8 @@ _(DNS_ENABLE_DISABLE, dns_enable_disable) \ _(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \ _(DNS_RESOLVE_NAME, dns_resolve_name) \ _(DNS_RESOLVE_IP, dns_resolve_ip) \ -_(SESSION_RULE_ADD_DEL, session_rule_add_del) +_(SESSION_RULE_ADD_DEL, session_rule_add_del) \ +_(OUTPUT_ACL_SET_INTERFACE, output_acl_set_interface) void vl_msg_api_custom_dump_configure (api_main_t * am) { diff --git a/test/test_classifier.py b/test/test_classifier.py index a43f7a3d0f6..1753feff66a 100644 --- a/test/test_classifier.py +++ b/test/test_classifier.py @@ -3,6 +3,7 @@ import unittest import socket import binascii +import sys from framework import VppTestCase, VppTestRunner @@ -275,6 +276,20 @@ class TestClassifier(VppTestCase): ip4_table_index=table_index) self.assertIsNotNone(r, msg='No response msg for acl_set_interface') + def output_acl_set_interface(self, intf, table_index, is_add=1): + """Configure Output ACL interface + + :param VppInterface intf: Interface to apply Output ACL feature. + :param int table_index: table index to identify classify table. + :param int is_add: option to configure classify session. + - enable(1) or disable(0) + """ + r = self.vapi.output_acl_set_interface( + is_add, + intf.sw_if_index, + ip4_table_index=table_index) + self.assertIsNotNone(r, msg='No response msg for acl_set_interface') + def test_acl_ip(self): """ IP ACL test @@ -304,6 +319,36 @@ class TestClassifier(VppTestCase): self.pg2.assert_nothing_captured(remark="packets forwarded") self.pg3.assert_nothing_captured(remark="packets forwarded") + def test_acl_ip_out(self): + """ Output IP ACL test + + Test scenario for basic IP ACL with source IP + - Create IPv4 stream for pg1 -> pg0 interface. + - Create ACL with source IP address. + - Send and verify received packets on pg0 interface. + """ + + # Basic ACL testing with source IP + pkts = self.create_stream(self.pg1, self.pg0, self.pg_if_packet_sizes) + self.pg1.add_stream(pkts) + + self.create_classify_table('ip', self.build_ip_mask(src_ip='ffffffff'), + data_offset=0) + self.create_classify_session( + self.pg1, self.acl_tbl_idx.get('ip'), + self.build_ip_match(src_ip=self.pg1.remote_ip4)) + self.output_acl_set_interface(self.pg0, self.acl_tbl_idx.get('ip')) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + pkts = self.pg0.get_capture(len(pkts)) + self.verify_capture(self.pg0, pkts) + self.output_acl_set_interface(self.pg0, self.acl_tbl_idx.get('ip'), 0) + self.pg1.assert_nothing_captured(remark="packets forwarded") + self.pg2.assert_nothing_captured(remark="packets forwarded") + self.pg3.assert_nothing_captured(remark="packets forwarded") + def test_acl_mac(self): """ MAC ACL test diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index fd6240576b3..242f51cde62 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -2125,6 +2125,29 @@ class VppPapiProvider(object): 'l2_table_index': l2_table_index, 'is_add': is_add}) + def output_acl_set_interface( + self, + is_add, + sw_if_index, + ip4_table_index=0xFFFFFFFF, + ip6_table_index=0xFFFFFFFF, + l2_table_index=0xFFFFFFFF): + """ + :param is_add: + :param sw_if_index: + :param ip4_table_index: (Default value = 0xFFFFFFFF) + :param ip6_table_index: (Default value = 0xFFFFFFFF) + :param l2_table_index: (Default value = 0xFFFFFFFF) + """ + + return self.api( + self.papi.output_acl_set_interface, + {'sw_if_index': sw_if_index, + 'ip4_table_index': ip4_table_index, + 'ip6_table_index': ip6_table_index, + 'l2_table_index': l2_table_index, + 'is_add': is_add}) + def set_ipfix_exporter( self, collector_address, |