X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Facl%2Fdataplane_node.c;h=5034f945d0ea053a81cb0911c3d0cbb6dc5ad8bc;hb=5cd31ec9405d2bb2fbc8152a08c4cfb64f2a8e73;hp=98e966189d86cd5bb5250879210d2caf84b72a22;hpb=3e0ee6ec3ce1d3f32c1faca7514048e55412220e;p=vpp.git diff --git a/src/plugins/acl/dataplane_node.c b/src/plugins/acl/dataplane_node.c index 98e966189d8..5034f945d0e 100644 --- a/src/plugins/acl/dataplane_node.c +++ b/src/plugins/acl/dataplane_node.c @@ -66,498 +66,867 @@ typedef enum /* *INDENT-ON* */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u16 ethertype; +} nonip_in_out_trace_t; -always_inline uword -acl_fa_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame, int is_ip6, - int is_input, int is_l2_path, u32 * l2_feat_next_node_index, - vlib_node_registration_t * acl_fa_node) +/* packet trace format function */ +static u8 * +format_nonip_in_out_trace (u8 * s, u32 is_output, va_list * args) { - u32 n_left_from, *from, *to_next; - acl_fa_next_t next_index; - u32 pkts_acl_checked = 0; - u32 pkts_new_session = 0; - u32 pkts_exist_session = 0; - u32 pkts_acl_permit = 0; - u32 pkts_restart_session_timer = 0; - u32 trace_bitmap = 0; - acl_main_t *am = &acl_main; - fa_5tuple_t fa_5tuple, kv_sess; - clib_bihash_kv_40_8_t value_sess; - vlib_node_runtime_t *error_node; - u64 now = clib_cpu_time_now (); - uword thread_index = os_get_thread_index (); - acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index]; + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nonip_in_out_trace_t *t = va_arg (*args, nonip_in_out_trace_t *); - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; + s = format (s, "%s: sw_if_index %d next_index %x ethertype %x", + is_output ? "OUT-ETHER-WHITELIST" : "IN-ETHER-WHITELIST", + t->sw_if_index, t->next_index, t->ethertype); + return s; +} - error_node = vlib_node_get_runtime (vm, acl_fa_node->index); +static u8 * +format_l2_nonip_in_trace (u8 * s, va_list * args) +{ + return format_nonip_in_out_trace (s, 0, args); +} - while (n_left_from > 0) - { - u32 n_left_to_next; +static u8 * +format_l2_nonip_out_trace (u8 * s, va_list * args) +{ + return format_nonip_in_out_trace (s, 1, args); +} - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); +#define foreach_nonip_in_error \ +_(DROP, "dropped inbound non-whitelisted non-ip packets") \ +_(PERMIT, "permitted inbound whitelisted non-ip packets") \ - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = 0; - u8 action = 0; - u32 sw_if_index0; - u32 lc_index0; - int acl_check_needed = 1; - u32 match_acl_in_index = ~0; - u32 match_acl_pos = ~0; - u32 match_rule_index = ~0; - u8 error0 = 0; - u32 valid_new_sess; - - /* 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); - - if (is_input) - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - else - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - - if (is_input) - lc_index0 = am->input_lc_index_by_sw_if_index[sw_if_index0]; - else - lc_index0 = am->output_lc_index_by_sw_if_index[sw_if_index0]; - - u32 **p_epoch_vec = - is_input ? &am->input_policy_epoch_by_sw_if_index : - &am->output_policy_epoch_by_sw_if_index; - u16 current_policy_epoch = - sw_if_index0 < vec_len (*p_epoch_vec) ? vec_elt (*p_epoch_vec, - sw_if_index0) - : (is_input * FA_POLICY_EPOCH_IS_INPUT); - /* - * Extract the L3/L4 matching info into a 5-tuple structure, - * then create a session key whose layout is independent on forward or reverse - * direction of the packet. - */ - - acl_plugin_fill_5tuple_inline (lc_index0, b0, is_ip6, is_input, - is_l2_path, - (fa_5tuple_opaque_t *) & fa_5tuple); - fa_5tuple.l4.lsb_of_sw_if_index = sw_if_index0 & 0xffff; - valid_new_sess = - acl_make_5tuple_session_key (am, is_input, is_ip6, sw_if_index0, - &fa_5tuple, &kv_sess); - // XXDEL fa_5tuple.pkt.is_input = is_input; - fa_5tuple.pkt.mask_type_index_lsb = ~0; -#ifdef FA_NODE_VERBOSE_DEBUG - clib_warning - ("ACL_FA_NODE_DBG: session 5-tuple %016llx %016llx %016llx %016llx %016llx %016llx", - kv_sess.kv.key[0], kv_sess.kv.key[1], kv_sess.kv.key[2], - kv_sess.kv.key[3], kv_sess.kv.key[4], kv_sess.kv.value); - clib_warning - ("ACL_FA_NODE_DBG: packet 5-tuple %016llx %016llx %016llx %016llx %016llx %016llx", - fa_5tuple.kv.key[0], fa_5tuple.kv.key[1], fa_5tuple.kv.key[2], - fa_5tuple.kv.key[3], fa_5tuple.kv.key[4], fa_5tuple.kv.value); -#endif - /* Try to match an existing session first */ +#define foreach_nonip_out_error \ +_(DROP, "dropped outbound non-whitelisted non-ip packets") \ +_(PERMIT, "permitted outbound whitelisted non-ip packets") \ - if (acl_fa_ifc_has_sessions (am, sw_if_index0)) - { - if (acl_fa_find_session - (am, sw_if_index0, &kv_sess, &value_sess)) - { - trace_bitmap |= 0x80000000; - error0 = ACL_FA_ERROR_ACL_EXIST_SESSION; - fa_full_session_id_t f_sess_id; - f_sess_id.as_u64 = value_sess.value; - ASSERT (f_sess_id.thread_index < vec_len (vlib_mains)); +/* *INDENT-OFF* */ - fa_session_t *sess = - get_session_ptr (am, f_sess_id.thread_index, - f_sess_id.session_index); - int old_timeout_type = - fa_session_get_timeout_type (am, sess); - action = - acl_fa_track_session (am, is_input, sw_if_index0, now, - sess, &fa_5tuple); - /* expose the session id to the tracer */ - match_rule_index = f_sess_id.session_index; - int new_timeout_type = - fa_session_get_timeout_type (am, sess); - acl_check_needed = 0; - pkts_exist_session += 1; - /* Tracking might have changed the session timeout type, e.g. from transient to established */ - if (PREDICT_FALSE (old_timeout_type != new_timeout_type)) - { - acl_fa_restart_timer_for_session (am, now, f_sess_id); - pkts_restart_session_timer++; - trace_bitmap |= - 0x00010000 + ((0xff & old_timeout_type) << 8) + - (0xff & new_timeout_type); - } - /* - * I estimate the likelihood to be very low - the VPP needs - * to have >64K interfaces to start with and then on - * exactly 64K indices apart needs to be exactly the same - * 5-tuple... Anyway, since this probability is nonzero - - * print an error and drop the unlucky packet. - * If this shows up in real world, we would need to bump - * the hash key length. - */ - if (PREDICT_FALSE (sess->sw_if_index != sw_if_index0)) - { - clib_warning - ("BUG: session LSB16(sw_if_index) and 5-tuple collision!"); - acl_check_needed = 0; - action = 0; - } - if (PREDICT_FALSE (am->reclassify_sessions)) - { - /* if the MSB of policy epoch matches but not the LSB means it is a stale session */ - if ((0 == - ((current_policy_epoch ^ - f_sess_id.intf_policy_epoch) & - FA_POLICY_EPOCH_IS_INPUT)) - && (current_policy_epoch != - f_sess_id.intf_policy_epoch)) - { - /* delete session and increment the counter */ - vec_validate - (pw->fa_session_epoch_change_by_sw_if_index, - sw_if_index0); - vec_elt (pw->fa_session_epoch_change_by_sw_if_index, - sw_if_index0)++; - if (acl_fa_conn_list_delete_session (am, f_sess_id)) - { - /* delete the session only if we were able to unlink it */ - acl_fa_delete_session (am, sw_if_index0, - f_sess_id); - } - acl_check_needed = 1; - trace_bitmap |= 0x40000000; - } - } - } - } +typedef enum +{ +#define _(sym,str) FA_IN_NONIP_ERROR_##sym, + foreach_nonip_in_error +#undef _ + FA_IN_NONIP_N_ERROR, +} l2_in_feat_arc_error_t; - if (acl_check_needed) - { - action = 0; /* deny by default */ - acl_plugin_match_5tuple_inline (lc_index0, - (fa_5tuple_opaque_t *) & - fa_5tuple, is_ip6, &action, - &match_acl_pos, - &match_acl_in_index, - &match_rule_index, - &trace_bitmap); - error0 = action; - if (1 == action) - pkts_acl_permit += 1; - if (2 == action) - { - if (!acl_fa_can_add_session (am, is_input, sw_if_index0)) - acl_fa_try_recycle_session (am, is_input, thread_index, - sw_if_index0); +static char *fa_in_nonip_error_strings[] = { +#define _(sym,string) string, + foreach_nonip_in_error +#undef _ +}; - if (acl_fa_can_add_session (am, is_input, sw_if_index0)) - { - if (PREDICT_TRUE (valid_new_sess)) - { - fa_session_t *sess = - acl_fa_add_session (am, is_input, - sw_if_index0, - now, &kv_sess, - current_policy_epoch); - acl_fa_track_session (am, is_input, sw_if_index0, - now, sess, &fa_5tuple); - pkts_new_session += 1; - } - else - { - /* - * ICMP packets with non-icmp_valid_new type will be - * forwared without being dropped. - */ - action = 1; - pkts_acl_permit += 1; - } - } - else - { - action = 0; - error0 = ACL_FA_ERROR_ACL_TOO_MANY_SESSIONS; - } - } - } +typedef enum +{ +#define _(sym,str) FA_OUT_NONIP_ERROR_##sym, + foreach_nonip_out_error +#undef _ + FA_OUT_NONIP_N_ERROR, +} l2_out_feat_arc_error_t; +static char *fa_out_nonip_error_strings[] = { +#define _(sym,string) string, + foreach_nonip_out_error +#undef _ +}; +/* *INDENT-ON* */ - if (action > 0) - { - if (is_l2_path) - next0 = vnet_l2_feature_next (b0, l2_feat_next_node_index, 0); - else - vnet_feature_next (sw_if_index0, &next0, b0); - } -#ifdef FA_NODE_VERBOSE_DEBUG - clib_warning - ("ACL_FA_NODE_DBG: sw_if_index %d lc_index %d action %d acl_index %d rule_index %d", - sw_if_index0, lc_index0, action, match_acl_in_index, - match_rule_index); -#endif +always_inline int +is_permitted_ethertype (acl_main_t * am, int sw_if_index0, int is_output, + u16 ethertype) +{ + u16 **v = is_output + ? am->output_etype_whitelist_by_sw_if_index + : am->input_etype_whitelist_by_sw_if_index; + u16 *whitelist = vec_elt (v, sw_if_index0); + int i; + + if (vec_len (whitelist) == 0) + return 1; + + for (i = 0; i < vec_len (whitelist); i++) + if (whitelist[i] == ethertype) + return 1; + return 0; +} - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - acl_fa_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->lc_index = lc_index0; - t->next_index = next0; - t->match_acl_in_index = match_acl_in_index; - t->match_rule_index = match_rule_index; - t->packet_info[0] = fa_5tuple.kv.key[0]; - t->packet_info[1] = fa_5tuple.kv.key[1]; - t->packet_info[2] = fa_5tuple.kv.key[2]; - t->packet_info[3] = fa_5tuple.kv.key[3]; - t->packet_info[4] = fa_5tuple.kv.key[4]; - t->packet_info[5] = fa_5tuple.kv.value; - t->action = action; - t->trace_bitmap = trace_bitmap; - } +#define get_u16(addr) ( *((u16 *)(addr)) ) + +always_inline uword +nonip_in_out_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_output) +{ + acl_main_t *am = &acl_main; + u32 n_left, *from; + u16 nexts[VLIB_FRAME_SIZE], *next; + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + vlib_node_runtime_t *error_node; + + from = vlib_frame_vector_args (frame); + error_node = vlib_node_get_runtime (vm, node->node_index); + vlib_get_buffers (vm, from, bufs, frame->n_vectors); + /* set the initial values for the current buffer the next pointers */ + b = bufs; + next = nexts; + + n_left = frame->n_vectors; + while (n_left > 0) + { + u32 next_index = 0; + u32 sw_if_index0 = + vnet_buffer (b[0])->sw_if_index[is_output ? VLIB_TX : VLIB_RX]; + u16 ethertype = 0; + + int error0 = 0; - next0 = next0 < node->n_next_nodes ? next0 : 0; - if (0 == next0) - b0->error = error_node->errors[error0]; + ethernet_header_t *h0 = vlib_buffer_get_current (b[0]); + u8 *l3h0 = (u8 *) h0 + vnet_buffer (b[0])->l2.l2_len; + ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2)); - pkts_acl_checked += 1; + if (is_permitted_ethertype (am, sw_if_index0, is_output, ethertype)) + vnet_feature_next (&next_index, b[0]); - /* 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); + next[0] = next_index; + + if (0 == next[0]) + b[0]->error = error_node->errors[error0]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b[0]->flags & VLIB_BUFFER_IS_TRACED))) + { + nonip_in_out_trace_t *t = + vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->ethertype = ethertype; + t->next_index = next[0]; } + next[0] = next[0] < node->n_next_nodes ? next[0] : 0; - vlib_put_next_frame (vm, node, next_index, n_left_to_next); + next++; + b++; + n_left--; } + vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); - vlib_node_increment_counter (vm, acl_fa_node->index, - ACL_FA_ERROR_ACL_CHECK, pkts_acl_checked); - vlib_node_increment_counter (vm, acl_fa_node->index, - ACL_FA_ERROR_ACL_PERMIT, pkts_acl_permit); - vlib_node_increment_counter (vm, acl_fa_node->index, - ACL_FA_ERROR_ACL_NEW_SESSION, - pkts_new_session); - vlib_node_increment_counter (vm, acl_fa_node->index, - ACL_FA_ERROR_ACL_EXIST_SESSION, - pkts_exist_session); - vlib_node_increment_counter (vm, acl_fa_node->index, - ACL_FA_ERROR_ACL_RESTART_SESSION_TIMER, - pkts_restart_session_timer); return frame->n_vectors; } -vlib_node_function_t __clib_weak acl_in_ip4_l2_node_fn_avx512; -vlib_node_function_t __clib_weak acl_in_ip4_l2_node_fn_avx2; +VLIB_NODE_FN (acl_in_nonip_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return nonip_in_out_node_fn (vm, node, frame, 0); +} -vlib_node_function_t __clib_weak acl_out_ip4_l2_node_fn_avx512; -vlib_node_function_t __clib_weak acl_out_ip4_l2_node_fn_avx2; +VLIB_NODE_FN (acl_out_nonip_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return nonip_in_out_node_fn (vm, node, frame, 1); +} -vlib_node_function_t __clib_weak acl_in_ip6_l2_node_fn_avx512; -vlib_node_function_t __clib_weak acl_in_ip6_l2_node_fn_avx2; -vlib_node_function_t __clib_weak acl_out_ip6_l2_node_fn_avx512; -vlib_node_function_t __clib_weak acl_out_ip6_l2_node_fn_avx2; +/* *INDENT-OFF* */ -vlib_node_function_t __clib_weak acl_in_ip4_fa_node_fn_avx512; -vlib_node_function_t __clib_weak acl_in_ip4_fa_node_fn_avx2; +VLIB_REGISTER_NODE (acl_in_nonip_node) = +{ + .name = "acl-plugin-in-nonip-l2", + .vector_size = sizeof (u32), + .format_trace = format_l2_nonip_in_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (fa_in_nonip_error_strings), + .error_strings = fa_in_nonip_error_strings, + .n_next_nodes = ACL_FA_N_NEXT, + .next_nodes = + { + [ACL_FA_ERROR_DROP] = "error-drop", + } +}; -vlib_node_function_t __clib_weak acl_out_ip4_fa_node_fn_avx512; -vlib_node_function_t __clib_weak acl_out_ip4_fa_node_fn_avx2; +VNET_FEATURE_INIT (acl_in_l2_nonip_fa_feature, static) = +{ + .arc_name = "l2-input-nonip", + .node_name = "acl-plugin-in-nonip-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; -vlib_node_function_t __clib_weak acl_in_ip6_fa_node_fn_avx512; -vlib_node_function_t __clib_weak acl_in_ip6_fa_node_fn_avx2; +VLIB_REGISTER_NODE (acl_out_nonip_node) = +{ + .name = "acl-plugin-out-nonip-l2", + .vector_size = sizeof (u32), + .format_trace = format_l2_nonip_out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (fa_out_nonip_error_strings), + .error_strings = fa_out_nonip_error_strings, + .n_next_nodes = ACL_FA_N_NEXT, + .next_nodes = + { + [ACL_FA_ERROR_DROP] = "error-drop", + } +}; + +VNET_FEATURE_INIT (acl_out_l2_nonip_fa_feature, static) = +{ + .arc_name = "l2-output-nonip", + .node_name = "acl-plugin-out-nonip-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + +/* *INDENT-ON* */ -vlib_node_function_t __clib_weak acl_out_ip6_fa_node_fn_avx512; -vlib_node_function_t __clib_weak acl_out_ip6_fa_node_fn_avx2; -vlib_node_registration_t acl_in_l2_ip6_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_in_ip6_l2_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline u16 +get_current_policy_epoch (acl_main_t * am, int is_input, u32 sw_if_index0) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 1, 1, 1, - am->fa_acl_in_ip6_l2_node_feat_next_node_index, - &acl_in_l2_ip6_node); + u32 **p_epoch_vec = + is_input ? &am->input_policy_epoch_by_sw_if_index : + &am->output_policy_epoch_by_sw_if_index; + u16 current_policy_epoch = + sw_if_index0 < vec_len (*p_epoch_vec) ? vec_elt (*p_epoch_vec, + sw_if_index0) + : (is_input * FA_POLICY_EPOCH_IS_INPUT); + return current_policy_epoch; } -vlib_node_registration_t acl_in_l2_ip4_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_in_ip4_l2_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline void +maybe_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_buffer_t * b, u32 sw_if_index0, u32 lc_index0, + u16 next0, int match_acl_in_index, int match_rule_index, + fa_5tuple_t * fa_5tuple, u8 action, u32 trace_bitmap) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 0, 1, 1, - am->fa_acl_in_ip4_l2_node_feat_next_node_index, - &acl_in_l2_ip4_node); + if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED)) + { + acl_fa_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->lc_index = lc_index0; + t->next_index = next0; + t->match_acl_in_index = match_acl_in_index; + t->match_rule_index = match_rule_index; + t->packet_info[0] = fa_5tuple->kv_40_8.key[0]; + t->packet_info[1] = fa_5tuple->kv_40_8.key[1]; + t->packet_info[2] = fa_5tuple->kv_40_8.key[2]; + t->packet_info[3] = fa_5tuple->kv_40_8.key[3]; + t->packet_info[4] = fa_5tuple->kv_40_8.key[4]; + t->packet_info[5] = fa_5tuple->kv_40_8.value; + t->action = action; + t->trace_bitmap = trace_bitmap; + } } -vlib_node_registration_t acl_out_l2_ip6_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_out_ip6_l2_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) + +always_inline int +stale_session_deleted (acl_main_t * am, int is_input, + acl_fa_per_worker_data_t * pw, u64 now, + u32 sw_if_index0, fa_full_session_id_t f_sess_id) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 1, 0, 1, - am->fa_acl_out_ip6_l2_node_feat_next_node_index, - &acl_out_l2_ip6_node); + u16 current_policy_epoch = + get_current_policy_epoch (am, is_input, sw_if_index0); + + /* if the MSB of policy epoch matches but not the LSB means it is a stale session */ + if ((0 == + ((current_policy_epoch ^ + f_sess_id.intf_policy_epoch) & + FA_POLICY_EPOCH_IS_INPUT)) + && (current_policy_epoch != f_sess_id.intf_policy_epoch)) + { + /* delete session and increment the counter */ + vec_validate (pw->fa_session_epoch_change_by_sw_if_index, sw_if_index0); + vec_elt (pw->fa_session_epoch_change_by_sw_if_index, sw_if_index0)++; + if (acl_fa_conn_list_delete_session (am, f_sess_id, now)) + { + /* delete the session only if we were able to unlink it */ + acl_fa_two_stage_delete_session (am, sw_if_index0, f_sess_id, now); + } + return 1; + } + else + return 0; } -vlib_node_registration_t acl_out_l2_ip4_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_out_ip4_l2_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) + + + + +always_inline void +get_sw_if_index_xN (int vector_sz, int is_input, vlib_buffer_t ** b, + u32 * out_sw_if_index) { - acl_main_t *am = &acl_main; - return acl_fa_node_fn (vm, node, frame, 0, 0, 1, - am->fa_acl_out_ip4_l2_node_feat_next_node_index, - &acl_out_l2_ip4_node); + int ii; + for (ii = 0; ii < vector_sz; ii++) + if (is_input) + out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_RX]; + else + out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_TX]; } -/**** L3 processing path nodes ****/ - -vlib_node_registration_t acl_in_fa_ip6_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_in_ip6_fa_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline void +fill_5tuple_xN (int vector_sz, acl_main_t * am, int is_ip6, int is_input, + int is_l2_path, vlib_buffer_t ** b, u32 * sw_if_index, + fa_5tuple_t * out_fa_5tuple) { - return acl_fa_node_fn (vm, node, frame, 1, 1, 0, 0, &acl_in_fa_ip6_node); + int ii; + for (ii = 0; ii < vector_sz; ii++) + acl_fill_5tuple (am, sw_if_index[ii], b[ii], is_ip6, + is_input, is_l2_path, &out_fa_5tuple[ii]); } -vlib_node_registration_t acl_in_fa_ip4_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_in_ip4_fa_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline void +make_session_hash_xN (int vector_sz, acl_main_t * am, int is_ip6, + u32 * sw_if_index, fa_5tuple_t * fa_5tuple, + u64 * out_hash) { - return acl_fa_node_fn (vm, node, frame, 0, 1, 0, 0, &acl_in_fa_ip4_node); + int ii; + for (ii = 0; ii < vector_sz; ii++) + out_hash[ii] = + acl_fa_make_session_hash (am, is_ip6, sw_if_index[ii], &fa_5tuple[ii]); } -vlib_node_registration_t acl_out_fa_ip6_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_out_ip6_fa_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline void +prefetch_session_entry (acl_main_t * am, fa_full_session_id_t f_sess_id) { - return acl_fa_node_fn (vm, node, frame, 1, 0, 0, 0, &acl_out_fa_ip6_node); + fa_session_t *sess = get_session_ptr_no_check (am, f_sess_id.thread_index, + f_sess_id.session_index); + CLIB_PREFETCH (sess, 2 * CLIB_CACHE_LINE_BYTES, STORE); } -vlib_node_registration_t acl_out_fa_ip4_node; -uword CLIB_CPU_OPTIMIZED -CLIB_MULTIARCH_FN (acl_out_ip4_fa_node_fn) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame) +always_inline u8 +process_established_session (vlib_main_t * vm, acl_main_t * am, + u32 counter_node_index, int is_input, u64 now, + fa_full_session_id_t f_sess_id, + u32 * sw_if_index, fa_5tuple_t * fa_5tuple, + u32 pkt_len, int node_trace_on, + u32 * trace_bitmap) { - return acl_fa_node_fn (vm, node, frame, 0, 0, 0, 0, &acl_out_fa_ip4_node); + u8 action = 0; + fa_session_t *sess = get_session_ptr_no_check (am, f_sess_id.thread_index, + f_sess_id.session_index); + + int old_timeout_type = fa_session_get_timeout_type (am, sess); + action = + acl_fa_track_session (am, is_input, sw_if_index[0], now, + sess, &fa_5tuple[0], pkt_len); + int new_timeout_type = fa_session_get_timeout_type (am, sess); + /* Tracking might have changed the session timeout type, e.g. from transient to established */ + if (PREDICT_FALSE (old_timeout_type != new_timeout_type)) + { + acl_fa_restart_timer_for_session (am, now, f_sess_id); + vlib_node_increment_counter (vm, counter_node_index, + ACL_FA_ERROR_ACL_RESTART_SESSION_TIMER, 1); + if (node_trace_on) + *trace_bitmap |= + 0x00010000 + ((0xff & old_timeout_type) << 8) + + (0xff & new_timeout_type); + } + /* + * I estimate the likelihood to be very low - the VPP needs + * to have >64K interfaces to start with and then on + * exactly 64K indices apart needs to be exactly the same + * 5-tuple... Anyway, since this probability is nonzero - + * print an error and drop the unlucky packet. + * If this shows up in real world, we would need to bump + * the hash key length. + */ + if (PREDICT_FALSE (sess->sw_if_index != sw_if_index[0])) + { + clib_warning + ("BUG: session LSB16(sw_if_index)=%d and 5-tuple=%d collision!", + sess->sw_if_index, sw_if_index[0]); + action = 0; + } + return action; + } +#define ACL_PLUGIN_VECTOR_SIZE 4 +#define ACL_PLUGIN_PREFETCH_GAP 3 + +always_inline void +acl_fa_node_common_prepare_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, int is_ip6, int is_input, + int is_l2_path, int with_stateful_datapath) + /* , int node_trace_on, + int reclassify_sessions) */ +{ + u32 n_left, *from; + acl_main_t *am = &acl_main; + uword thread_index = os_get_thread_index (); + acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index]; + + vlib_buffer_t **b; + u32 *sw_if_index; + fa_5tuple_t *fa_5tuple; + u64 *hash; + + + + from = vlib_frame_vector_args (frame); + vlib_get_buffers (vm, from, pw->bufs, frame->n_vectors); + + /* set the initial values for the current buffer the next pointers */ + b = pw->bufs; + sw_if_index = pw->sw_if_indices; + fa_5tuple = pw->fa_5tuples; + hash = pw->hashes; + + + /* + * fill the sw_if_index, 5tuple and session hash, + * First in strides of size ACL_PLUGIN_VECTOR_SIZE, + * with buffer prefetch being + * ACL_PLUGIN_PREFETCH_GAP * ACL_PLUGIN_VECTOR_SIZE entries + * in front. Then with a simple single loop. + */ + + n_left = frame->n_vectors; + while (n_left >= (ACL_PLUGIN_PREFETCH_GAP + 1) * ACL_PLUGIN_VECTOR_SIZE) + { + const int vec_sz = ACL_PLUGIN_VECTOR_SIZE; + { + int ii; + for (ii = ACL_PLUGIN_PREFETCH_GAP * vec_sz; + ii < (ACL_PLUGIN_PREFETCH_GAP + 1) * vec_sz; ii++) + { + CLIB_PREFETCH (b[ii], CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (b[ii]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + } + } + + + get_sw_if_index_xN (vec_sz, is_input, b, sw_if_index); + fill_5tuple_xN (vec_sz, am, is_ip6, is_input, is_l2_path, &b[0], + &sw_if_index[0], &fa_5tuple[0]); + if (with_stateful_datapath) + make_session_hash_xN (vec_sz, am, is_ip6, &sw_if_index[0], + &fa_5tuple[0], &hash[0]); + + n_left -= vec_sz; + + fa_5tuple += vec_sz; + b += vec_sz; + sw_if_index += vec_sz; + hash += vec_sz; + } + + while (n_left > 0) + { + const int vec_sz = 1; + + get_sw_if_index_xN (vec_sz, is_input, b, sw_if_index); + fill_5tuple_xN (vec_sz, am, is_ip6, is_input, is_l2_path, &b[0], + &sw_if_index[0], &fa_5tuple[0]); + if (with_stateful_datapath) + make_session_hash_xN (vec_sz, am, is_ip6, &sw_if_index[0], + &fa_5tuple[0], &hash[0]); + + n_left -= vec_sz; + + fa_5tuple += vec_sz; + b += vec_sz; + sw_if_index += vec_sz; + hash += vec_sz; + } +} -#if __x86_64__ -static void __clib_constructor -acl_plugin_multiarch_select (void) +always_inline uword +acl_fa_inner_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_ip6, int is_input, int is_l2_path, + int with_stateful_datapath, int node_trace_on, + int reclassify_sessions) { - if (acl_in_ip4_l2_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_in_l2_ip4_node.function = acl_in_ip4_l2_node_fn_avx512; - else if (acl_in_ip4_l2_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_in_l2_ip4_node.function = acl_in_ip4_l2_node_fn_avx2; + u32 n_left, *from; + u32 pkts_exist_session = 0; + u32 pkts_new_session = 0; + u32 pkts_acl_permit = 0; + u32 trace_bitmap = 0; + acl_main_t *am = &acl_main; + vlib_node_runtime_t *error_node; + vlib_error_t no_error_existing_session; + u64 now = clib_cpu_time_now (); + uword thread_index = os_get_thread_index (); + acl_fa_per_worker_data_t *pw = &am->per_worker_data[thread_index]; + + u16 *next; + vlib_buffer_t **b; + u32 *sw_if_index; + fa_5tuple_t *fa_5tuple; + u64 *hash; + /* for the delayed counters */ + u32 saved_matched_acl_index = 0; + u32 saved_matched_ace_index = 0; + u32 saved_packet_count = 0; + u32 saved_byte_count = 0; + + from = vlib_frame_vector_args (frame); + error_node = vlib_node_get_runtime (vm, node->node_index); + no_error_existing_session = + error_node->errors[ACL_FA_ERROR_ACL_EXIST_SESSION]; + + b = pw->bufs; + next = pw->nexts; + sw_if_index = pw->sw_if_indices; + fa_5tuple = pw->fa_5tuples; + hash = pw->hashes; + + /* + * Now the "hard" work of session lookups and ACL lookups for new sessions. + * Due to the complexity, do it for the time being in single loop with + * the pipeline of three prefetches: + * 1) bucket for the session bihash + * 2) data for the session bihash + * 3) worker session record + */ + + fa_full_session_id_t f_sess_id_next = {.as_u64 = ~0ULL }; + + /* find the "next" session so we can kickstart the pipeline */ + if (with_stateful_datapath) + acl_fa_find_session_with_hash (am, is_ip6, sw_if_index[0], hash[0], + &fa_5tuple[0], &f_sess_id_next.as_u64); + + n_left = frame->n_vectors; + while (n_left > 0) + { + u8 action = 0; + u32 lc_index0 = ~0; + int acl_check_needed = 1; + u32 match_acl_in_index = ~0; + u32 match_acl_pos = ~0; + u32 match_rule_index = ~0; + + next[0] = 0; /* drop by default */ + + /* Try to match an existing session first */ + + if (with_stateful_datapath) + { + fa_full_session_id_t f_sess_id = f_sess_id_next; + switch (n_left) + { + default: + acl_fa_prefetch_session_bucket_for_hash (am, is_ip6, hash[5]); + /* fallthrough */ + case 5: + case 4: + acl_fa_prefetch_session_data_for_hash (am, is_ip6, hash[3]); + /* fallthrough */ + case 3: + case 2: + acl_fa_find_session_with_hash (am, is_ip6, sw_if_index[1], + hash[1], &fa_5tuple[1], + &f_sess_id_next.as_u64); + if (f_sess_id_next.as_u64 != ~0ULL) + { + prefetch_session_entry (am, f_sess_id_next); + } + /* fallthrough */ + case 1: + if (f_sess_id.as_u64 != ~0ULL) + { + if (node_trace_on) + { + trace_bitmap |= 0x80000000; + } + ASSERT (f_sess_id.thread_index < vec_len (vlib_mains)); + b[0]->error = no_error_existing_session; + acl_check_needed = 0; + pkts_exist_session += 1; + action = + process_established_session (vm, am, node->node_index, + is_input, now, f_sess_id, + &sw_if_index[0], + &fa_5tuple[0], + b[0]->current_length, + node_trace_on, + &trace_bitmap); + + /* expose the session id to the tracer */ + if (node_trace_on) + { + match_rule_index = f_sess_id.session_index; + } + + if (reclassify_sessions) + { + if (PREDICT_FALSE + (stale_session_deleted + (am, is_input, pw, now, sw_if_index[0], + f_sess_id))) + { + acl_check_needed = 1; + if (node_trace_on) + { + trace_bitmap |= 0x40000000; + } + /* + * If we have just deleted the session, and the next + * buffer is the same 5-tuple, that session prediction + * is wrong, correct it. + */ + if ((f_sess_id_next.as_u64 != ~0ULL) + && 0 == memcmp (&fa_5tuple[1], &fa_5tuple[0], + sizeof (fa_5tuple[1]))) + f_sess_id_next.as_u64 = ~0ULL; + } + } + } + } + + if (acl_check_needed) + { + if (is_input) + lc_index0 = am->input_lc_index_by_sw_if_index[sw_if_index[0]]; + else + lc_index0 = + am->output_lc_index_by_sw_if_index[sw_if_index[0]]; + + action = 0; /* deny by default */ + int is_match = acl_plugin_match_5tuple_inline (am, lc_index0, + (fa_5tuple_opaque_t *) & fa_5tuple[0], is_ip6, + &action, + &match_acl_pos, + &match_acl_in_index, + &match_rule_index, + &trace_bitmap); + if (PREDICT_FALSE + (is_match && am->interface_acl_counters_enabled)) + { + u32 buf_len = vlib_buffer_length_in_chain (vm, b[0]); + vlib_increment_combined_counter (am->combined_acl_counters + + saved_matched_acl_index, + thread_index, + saved_matched_ace_index, + saved_packet_count, + saved_byte_count); + saved_matched_acl_index = match_acl_in_index; + saved_matched_ace_index = match_rule_index; + saved_packet_count = 1; + saved_byte_count = buf_len; + /* prefetch the counter that we are going to increment */ + vlib_prefetch_combined_counter (am->combined_acl_counters + + saved_matched_acl_index, + thread_index, + saved_matched_ace_index); + } + + b[0]->error = error_node->errors[action]; + + if (1 == action) + pkts_acl_permit++; + + if (2 == action) + { + if (!acl_fa_can_add_session (am, is_input, sw_if_index[0])) + acl_fa_try_recycle_session (am, is_input, + thread_index, + sw_if_index[0], now); + + if (acl_fa_can_add_session (am, is_input, sw_if_index[0])) + { + u16 current_policy_epoch = + get_current_policy_epoch (am, is_input, + sw_if_index[0]); + fa_full_session_id_t f_sess_id = + acl_fa_add_session (am, is_input, is_ip6, + sw_if_index[0], + now, &fa_5tuple[0], + current_policy_epoch); + + /* perform the accounting for the newly added session */ + process_established_session (vm, am, + node->node_index, + is_input, now, + f_sess_id, + &sw_if_index[0], + &fa_5tuple[0], + b[0]->current_length, + node_trace_on, + &trace_bitmap); + pkts_new_session++; + /* + * If the next 5tuple is the same and we just added the session, + * the f_sess_id_next can not be ~0. Correct it. + */ + if ((f_sess_id_next.as_u64 == ~0ULL) + && 0 == memcmp (&fa_5tuple[1], &fa_5tuple[0], + sizeof (fa_5tuple[1]))) + f_sess_id_next = f_sess_id; + } + else + { + action = 0; + b[0]->error = + error_node->errors + [ACL_FA_ERROR_ACL_TOO_MANY_SESSIONS]; + } + } - if (acl_out_ip4_l2_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_out_l2_ip4_node.function = acl_out_ip4_l2_node_fn_avx512; - else if (acl_out_ip4_l2_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_out_l2_ip4_node.function = acl_out_ip4_l2_node_fn_avx2; + } - if (acl_in_ip6_l2_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_in_l2_ip6_node.function = acl_in_ip6_l2_node_fn_avx512; - else if (acl_in_ip6_l2_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_in_l2_ip6_node.function = acl_in_ip6_l2_node_fn_avx2; + { + /* speculatively get the next0 */ + vnet_feature_next_u16 (&next[0], b[0]); + /* if the action is not deny - then use that next */ + next[0] = action ? next[0] : 0; + } - if (acl_out_ip6_l2_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_out_l2_ip6_node.function = acl_out_ip6_l2_node_fn_avx512; - else if (acl_out_ip6_l2_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_out_l2_ip6_node.function = acl_out_ip6_l2_node_fn_avx2; + if (node_trace_on) // PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE)) + { + maybe_trace_buffer (vm, node, b[0], sw_if_index[0], lc_index0, + next[0], match_acl_in_index, + match_rule_index, &fa_5tuple[0], action, + trace_bitmap); + } - if (acl_in_ip4_fa_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_in_fa_ip4_node.function = acl_in_ip4_fa_node_fn_avx512; - else if (acl_in_ip4_fa_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_in_fa_ip4_node.function = acl_in_ip4_fa_node_fn_avx2; + next++; + b++; + fa_5tuple++; + sw_if_index++; + hash++; + n_left -= 1; + } + } - if (acl_out_ip4_fa_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_out_fa_ip4_node.function = acl_out_ip4_fa_node_fn_avx512; - else if (acl_out_ip4_fa_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_out_fa_ip4_node.function = acl_out_ip4_fa_node_fn_avx2; + vlib_buffer_enqueue_to_next (vm, node, from, pw->nexts, frame->n_vectors); + + /* + * if we were had an acl match then we have a counter to increment. + * else it is all zeroes, so this will be harmless. + */ + vlib_increment_combined_counter (am->combined_acl_counters + + saved_matched_acl_index, + thread_index, + saved_matched_ace_index, + saved_packet_count, saved_byte_count); + + vlib_node_increment_counter (vm, node->node_index, + ACL_FA_ERROR_ACL_CHECK, frame->n_vectors); + vlib_node_increment_counter (vm, node->node_index, + ACL_FA_ERROR_ACL_EXIST_SESSION, + pkts_exist_session); + vlib_node_increment_counter (vm, node->node_index, + ACL_FA_ERROR_ACL_NEW_SESSION, + pkts_new_session); + vlib_node_increment_counter (vm, node->node_index, + ACL_FA_ERROR_ACL_PERMIT, pkts_acl_permit); + return frame->n_vectors; +} - if (acl_in_ip6_fa_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_in_fa_ip6_node.function = acl_in_ip6_fa_node_fn_avx512; - else if (acl_in_ip6_fa_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_in_fa_ip6_node.function = acl_in_ip6_fa_node_fn_avx2; +always_inline uword +acl_fa_outer_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int is_ip6, int is_input, int is_l2_path, + int do_stateful_datapath) +{ + acl_main_t *am = &acl_main; - if (acl_out_ip6_fa_node_fn_avx512 && clib_cpu_supports_avx512f ()) - acl_out_fa_ip6_node.function = acl_out_ip6_fa_node_fn_avx512; - else if (acl_out_ip6_fa_node_fn_avx2 && clib_cpu_supports_avx2 ()) - acl_out_fa_ip6_node.function = acl_out_ip6_fa_node_fn_avx2; + acl_fa_node_common_prepare_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, do_stateful_datapath); + if (am->reclassify_sessions) + { + if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE)) + return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, do_stateful_datapath, + 1 /* trace */ , + 1 /* reclassify */ ); + else + return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, do_stateful_datapath, 0, + 1 /* reclassify */ ); + } + else + { + if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE)) + return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, do_stateful_datapath, + 1 /* trace */ , + 0); + else + return acl_fa_inner_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, do_stateful_datapath, 0, 0); + } } -#endif +always_inline uword +acl_fa_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, int is_ip6, + int is_input, int is_l2_path) +{ + /* select the reclassify/no-reclassify version of the datapath */ + acl_main_t *am = &acl_main; + + if (am->fa_sessions_hash_is_initialized) + return acl_fa_outer_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, 1); + else + return acl_fa_outer_node_fn (vm, node, frame, is_ip6, is_input, + is_l2_path, 0); +} -#ifndef CLIB_MULTIARCH_VARIANT static u8 * format_fa_5tuple (u8 * s, va_list * args) { fa_5tuple_t *p5t = va_arg (*args, fa_5tuple_t *); + void *paddr0; + void *paddr1; + void *format_address_func; + void *ip_af; + void *ip_frag_txt = + p5t->pkt.is_nonfirst_fragment ? " non-initial fragment" : ""; + + if (p5t->pkt.is_ip6) + { + ip_af = "ip6"; + format_address_func = format_ip6_address; + paddr0 = &p5t->ip6_addr[0]; + paddr1 = &p5t->ip6_addr[1]; + } + else + { + ip_af = "ip4"; + format_address_func = format_ip4_address; + paddr0 = &p5t->ip4_addr[0]; + paddr1 = &p5t->ip4_addr[1]; + } - return format (s, "lc_index %d (lsb16 of sw_if_index %d) l3 %s%s %U -> %U" - " l4 proto %d l4_valid %d port %d -> %d tcp flags (%s) %02x rsvd %x", - p5t->pkt.lc_index, p5t->l4.lsb_of_sw_if_index, - p5t->pkt.is_ip6 ? "ip6" : "ip4", - p5t->pkt.is_nonfirst_fragment ? " non-initial fragment" : "", - format_ip46_address, &p5t->addr[0], - p5t->pkt.is_ip6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, - format_ip46_address, &p5t->addr[1], - p5t->pkt.is_ip6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, - p5t->l4.proto, p5t->pkt.l4_valid, p5t->l4.port[0], - p5t->l4.port[1], - p5t->pkt.tcp_flags_valid ? "valid" : "invalid", - p5t->pkt.tcp_flags, p5t->pkt.flags_reserved); + s = + format (s, "lc_index %d l3 %s%s ", p5t->pkt.lc_index, ip_af, ip_frag_txt); + s = + format (s, "%U -> %U ", format_address_func, paddr0, format_address_func, + paddr1); + s = format (s, "%U ", format_fa_session_l4_key, &p5t->l4); + s = format (s, "tcp flags (%s) %02x rsvd %x", + p5t->pkt.tcp_flags_valid ? "valid" : "invalid", + p5t->pkt.tcp_flags, p5t->pkt.flags_reserved); + return s; } +#ifndef CLIB_MARCH_VARIANT u8 * format_acl_plugin_5tuple (u8 * s, va_list * args) { return format_fa_5tuple (s, args); } +#endif /* packet trace format function */ -u8 * +static u8 * format_acl_plugin_trace (u8 * s, va_list * args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); @@ -578,7 +947,6 @@ format_acl_plugin_trace (u8 * s, va_list * args) return s; } - /* *INDENT-OFF* */ static char *acl_fa_error_strings[] = { @@ -587,9 +955,66 @@ static char *acl_fa_error_strings[] = { #undef _ }; +VLIB_NODE_FN (acl_in_l2_ip6_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 1, 1, 1); +} + +VLIB_NODE_FN (acl_in_l2_ip4_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 0, 1, 1); +} + +VLIB_NODE_FN (acl_out_l2_ip6_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 1, 0, 1); +} + +VLIB_NODE_FN (acl_out_l2_ip4_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 0, 0, 1); +} + +/**** L3 processing path nodes ****/ + +VLIB_NODE_FN (acl_in_fa_ip6_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 1, 1, 0); +} + +VLIB_NODE_FN (acl_in_fa_ip4_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 0, 1, 0); +} + +VLIB_NODE_FN (acl_out_fa_ip6_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 1, 0, 0); +} + +VLIB_NODE_FN (acl_out_fa_ip4_node) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return acl_fa_node_fn (vm, node, frame, 0, 0, 0); +} + VLIB_REGISTER_NODE (acl_in_l2_ip6_node) = { - .function = acl_in_ip6_l2_node_fn, .name = "acl-plugin-in-ip6-l2", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -603,9 +1028,15 @@ VLIB_REGISTER_NODE (acl_in_l2_ip6_node) = } }; +VNET_FEATURE_INIT (acl_in_l2_ip6_fa_feature, static) = +{ + .arc_name = "l2-input-ip6", + .node_name = "acl-plugin-in-ip6-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; + VLIB_REGISTER_NODE (acl_in_l2_ip4_node) = { - .function = acl_in_ip4_l2_node_fn, .name = "acl-plugin-in-ip4-l2", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -619,9 +1050,16 @@ VLIB_REGISTER_NODE (acl_in_l2_ip4_node) = } }; +VNET_FEATURE_INIT (acl_in_l2_ip4_fa_feature, static) = +{ + .arc_name = "l2-input-ip4", + .node_name = "acl-plugin-in-ip4-l2", + .runs_before = VNET_FEATURES ("l2-input-feat-arc-end"), +}; + + VLIB_REGISTER_NODE (acl_out_l2_ip6_node) = { - .function = acl_out_ip6_l2_node_fn, .name = "acl-plugin-out-ip6-l2", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -635,9 +1073,16 @@ VLIB_REGISTER_NODE (acl_out_l2_ip6_node) = } }; +VNET_FEATURE_INIT (acl_out_l2_ip6_fa_feature, static) = +{ + .arc_name = "l2-output-ip6", + .node_name = "acl-plugin-out-ip6-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + + VLIB_REGISTER_NODE (acl_out_l2_ip4_node) = { - .function = acl_out_ip4_l2_node_fn, .name = "acl-plugin-out-ip4-l2", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -651,10 +1096,16 @@ VLIB_REGISTER_NODE (acl_out_l2_ip4_node) = } }; +VNET_FEATURE_INIT (acl_out_l2_ip4_fa_feature, static) = +{ + .arc_name = "l2-output-ip4", + .node_name = "acl-plugin-out-ip4-l2", + .runs_before = VNET_FEATURES ("l2-output-feat-arc-end"), +}; + VLIB_REGISTER_NODE (acl_in_fa_ip6_node) = { - .function = acl_in_ip6_fa_node_fn, .name = "acl-plugin-in-ip6-fa", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -677,7 +1128,6 @@ VNET_FEATURE_INIT (acl_in_ip6_fa_feature, static) = VLIB_REGISTER_NODE (acl_in_fa_ip4_node) = { - .function = acl_in_ip4_fa_node_fn, .name = "acl-plugin-in-ip4-fa", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -701,7 +1151,6 @@ VNET_FEATURE_INIT (acl_in_ip4_fa_feature, static) = VLIB_REGISTER_NODE (acl_out_fa_ip6_node) = { - .function = acl_out_ip6_fa_node_fn, .name = "acl-plugin-out-ip6-fa", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -724,7 +1173,6 @@ VNET_FEATURE_INIT (acl_out_ip6_fa_feature, static) = VLIB_REGISTER_NODE (acl_out_fa_ip4_node) = { - .function = acl_out_ip4_fa_node_fn, .name = "acl-plugin-out-ip4-fa", .vector_size = sizeof (u32), .format_trace = format_acl_plugin_trace, @@ -745,7 +1193,6 @@ VNET_FEATURE_INIT (acl_out_ip4_fa_feature, static) = .node_name = "acl-plugin-out-ip4-fa", .runs_before = VNET_FEATURES ("interface-output"), }; -#endif /* *INDENT-ON* */