X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Facl%2Ffa_node.c;h=e12cbaa731d65c34203d2f9ee30dc650ba49107f;hb=d1b05647427c79cfd5322991bbe663fae65f37b5;hp=ac619a7298b65579fd307d02a386fe45b2d25b99;hpb=d2a59bed1e6b368a46608fd8ff631b770af8805f;p=vpp.git diff --git a/src/plugins/acl/fa_node.c b/src/plugins/acl/fa_node.c index ac619a7298b..e12cbaa731d 100644 --- a/src/plugins/acl/fa_node.c +++ b/src/plugins/acl/fa_node.c @@ -191,7 +191,21 @@ acl_match_5tuple (acl_main_t * am, u32 acl_index, fa_5tuple_t * pkt_5tuple, { if (pkt_5tuple->l4.proto != r->proto) continue; - /* A sanity check just to ensure what we jave just matched was a valid L4 extracted from the packet */ + + if (PREDICT_FALSE (pkt_5tuple->pkt.is_nonfirst_fragment && + am->l4_match_nonfirst_fragment)) + { + /* non-initial fragment with frag match configured - match this rule */ + *trace_bitmap |= 0x80000000; + *r_action = r->is_permit; + if (r_acl_match_p) + *r_acl_match_p = acl_index; + if (r_rule_match_p) + *r_rule_match_p = i; + return 1; + } + + /* A sanity check just to ensure we are about to match the ports extracted from the packet */ if (PREDICT_FALSE (!pkt_5tuple->pkt.l4_valid)) continue; @@ -312,6 +326,10 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6, l3_offset = 0; } + /* key[0..3] contains src/dst address and is cleared/set below */ + /* Remainder of the key and per-packet non-key data */ + p5tuple_pkt->kv.key[4] = 0; + p5tuple_pkt->kv.value = 0; if (is_ip6) { @@ -333,12 +351,33 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6, int need_skip_eh = clib_bitmap_get (am->fa_ipv6_known_eh_bitmap, proto); if (PREDICT_FALSE (need_skip_eh)) { - /* FIXME: add fragment header special handling. Currently causes treated as unknown header. */ while (need_skip_eh && offset_within_packet (b0, l4_offset)) { - u8 nwords = *(u8 *) get_ptr_to_offset (b0, 1 + l4_offset); - proto = *(u8 *) get_ptr_to_offset (b0, l4_offset); - l4_offset += 8 * (1 + (u16) nwords); + /* Fragment header needs special handling */ + if (PREDICT_FALSE(ACL_EH_FRAGMENT == proto)) + { + proto = *(u8 *) get_ptr_to_offset (b0, l4_offset); + u16 frag_offset; + clib_memcpy (&frag_offset, get_ptr_to_offset (b0, 2 + l4_offset), sizeof(frag_offset)); + frag_offset = ntohs(frag_offset) >> 3; + if (frag_offset) + { + p5tuple_pkt->pkt.is_nonfirst_fragment = 1; + /* invalidate L4 offset so we don't try to find L4 info */ + l4_offset += b0->current_length; + } + else + { + /* First fragment: skip the frag header and move on. */ + l4_offset += 8; + } + } + else + { + u8 nwords = *(u8 *) get_ptr_to_offset (b0, 1 + l4_offset); + proto = *(u8 *) get_ptr_to_offset (b0, l4_offset); + l4_offset += 8 * (1 + (u16) nwords); + } #ifdef FA_NODE_VERBOSE_DEBUG clib_warning ("ACL_FA_NODE_DBG: new proto: %d, new offset: %d", proto, l4_offset); @@ -369,13 +408,26 @@ acl_fill_5tuple (acl_main_t * am, vlib_buffer_t * b0, int is_ip6, offsetof (ip4_header_t, protocol) + l3_offset); l4_offset = l3_offset + sizeof (ip4_header_t); + u16 flags_and_fragment_offset; + clib_memcpy (&flags_and_fragment_offset, + get_ptr_to_offset (b0, + offsetof (ip4_header_t, + flags_and_fragment_offset)) + l3_offset, + sizeof(flags_and_fragment_offset)); + flags_and_fragment_offset = ntohs (flags_and_fragment_offset); + + /* non-initial fragments have non-zero offset */ + if ((PREDICT_FALSE(0xfff & flags_and_fragment_offset))) + { + p5tuple_pkt->pkt.is_nonfirst_fragment = 1; + /* invalidate L4 offset so we don't try to find L4 info */ + l4_offset += b0->current_length; + } + } - /* Remainder of the key and per-packet non-key data */ - p5tuple_pkt->kv.key[4] = 0; - p5tuple_pkt->kv.value = 0; + p5tuple_pkt->l4.proto = proto; if (PREDICT_TRUE (offset_within_packet (b0, l4_offset))) { - p5tuple_pkt->l4.proto = proto; p5tuple_pkt->pkt.l4_valid = 1; if (icmp_protos[is_ip6] == proto) { @@ -533,6 +585,10 @@ acl_fa_conn_list_add_session (acl_main_t * am, u32 sess_id) if (~0 == am->fa_conn_list_head[list_id]) { am->fa_conn_list_head[list_id] = sess_id; + /* If it is a first conn in any list, kick off the cleaner */ + vlib_process_signal_event (am->vlib_main, am->fa_cleaner_node_index, + ACL_FA_CLEANER_RESCHEDULE, 0); + } } @@ -556,7 +612,7 @@ acl_fa_conn_list_delete_session (acl_main_t *am, u32 sess_id) am->fa_conn_list_head[sess->link_list_id] = sess->link_next_idx; } if (am->fa_conn_list_tail[sess->link_list_id] == sess_id) { - am->fa_conn_list_tail[sess->link_list_id] = sess->link_next_idx; + am->fa_conn_list_tail[sess->link_list_id] = sess->link_prev_idx; } } @@ -982,14 +1038,6 @@ acl_out_ip4_fa_node_fn (vlib_main_t * vm, /* *INDENT-OFF* */ #define foreach_acl_fa_cleaner_error \ -_(EVENT_CYCLE, "event processing cycle") \ -_(TIMER_RESTARTED, "restarted session timers") \ -_(DELETED_SESSIONS, "deleted sessions") \ -_(ALREADY_DELETED, "timer event for already deleted session") \ -_(DELETE_BY_SW_IF_INDEX, "delete by sw_if_index event") \ -_(DELETE_BY_SW_IF_INDEX_OK, "delete by sw_if_index completed ok") \ -_(WAIT_WITHOUT_TIMEOUT, "process waits without timeout") \ -_(WAIT_WITH_TIMEOUT, "process waits with timeout") \ _(UNKNOWN_EVENT, "unknown event received") \ /* end of errors */ @@ -1067,7 +1115,7 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, f64 cpu_cps = vm->clib_time.clocks_per_second; u64 next_expire; /* We should call timer wheel at least twice a second */ - u64 max_timer_wait_interval = cpu_cps / 2; + u64 max_timer_wait_interval = cpu_cps / 2; am->fa_current_cleaner_timer_wait_interval = max_timer_wait_interval; u32 *expired = NULL; @@ -1079,10 +1127,24 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, { u32 count_deleted_sessions = 0; u32 count_already_deleted = 0; - u32 count_timer_restarted = 0; now = clib_cpu_time_now (); next_expire = now + am->fa_current_cleaner_timer_wait_interval; + int has_pending_conns = 0; + u8 tt; + for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) + { + if (~0 != am->fa_conn_list_head[tt]) + has_pending_conns = 1; + } + /* If no pending connections then no point in timing out */ + if (!has_pending_conns) + { + am->fa_cleaner_cnt_wait_without_timeout++; + (void) vlib_process_wait_for_event (vm); + event_type = vlib_process_get_events (vm, &event_data); + } + else { f64 timeout = ((i64) next_expire - (i64) now) / cpu_cps; if (timeout <= 0) @@ -1095,11 +1157,7 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, /* Timing wheel code is happier if it is called regularly */ if (timeout > 0.5) timeout = 0.5; - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node. - index, - ACL_FA_CLEANER_ERROR_WAIT_WITH_TIMEOUT, - 1); + am->fa_cleaner_cnt_wait_with_timeout++; (void) vlib_process_wait_for_event_or_clock (vm, timeout); event_type = vlib_process_get_events (vm, &event_data); } @@ -1119,11 +1177,7 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, uword *sw_if_index0; vec_foreach (sw_if_index0, event_data) { - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node. - index, - ACL_FA_CLEANER_ERROR_DELETE_BY_SW_IF_INDEX, - 1); + am->fa_cleaner_cnt_delete_by_sw_index++; #ifdef FA_NODE_VERBOSE_DEBUG clib_warning ("ACL_FA_NODE_CLEAN: ACL_FA_CLEANER_DELETE_BY_SW_IF_INDEX: %d", @@ -1134,11 +1188,7 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, acl_fa_clean_sessions_by_sw_if_index (am, *sw_if_index0, &count); count_deleted_sessions += count; - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node. - index, - ACL_FA_CLEANER_ERROR_DELETE_BY_SW_IF_INDEX_OK, - result); + am->fa_cleaner_cnt_delete_by_sw_index_ok += result; } } break; @@ -1147,17 +1197,21 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, clib_warning ("ACL plugin connection cleaner: unknown event %u", event_type); #endif - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node. - index, - ACL_FA_CLEANER_ERROR_UNKNOWN_EVENT, 1); + vlib_node_increment_counter (vm, + acl_fa_session_cleaner_process_node. + index, + ACL_FA_CLEANER_ERROR_UNKNOWN_EVENT, 1); + am->fa_cleaner_cnt_unknown_event++; break; } { u8 tt = 0; for(tt = 0; tt < ACL_N_TIMEOUTS; tt++) { - while((vec_len(expired) < 2*am->fa_max_deleted_sessions_per_interval) && (~0 != am->fa_conn_list_head[tt]) && (acl_fa_conn_has_timed_out(am, now, am->fa_conn_list_head[tt]))) { + while((vec_len(expired) < 2*am->fa_max_deleted_sessions_per_interval) + && (~0 != am->fa_conn_list_head[tt]) + && (acl_fa_conn_has_timed_out(am, now, + am->fa_conn_list_head[tt]))) { u32 sess_id = am->fa_conn_list_head[tt]; vec_add1(expired, sess_id); acl_fa_conn_list_delete_session(am, sess_id); @@ -1165,7 +1219,6 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, } } - u32 *psid = NULL; vec_foreach (psid, expired) { @@ -1181,15 +1234,22 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, /* clib_warning ("ACL_FA_NODE_CLEAN: Restarting timer for session %d", (int) session_index); */ - /* Pretend we did this in the past, at last_active moment */ - count_timer_restarted++; + /* There was activity on the session, so the idle timeout + has not passed. Enqueue for another time period. */ + + acl_fa_conn_list_add_session(am, session_index); + + /* FIXME: When/if moving to timer wheel, + pretend we did this in the past, + at last_active moment, so the timer is accurate */ + am->fa_cleaner_cnt_timer_restarted++; } else { /* clib_warning ("ACL_FA_NODE_CLEAN: Deleting session %d", (int) session_index); */ acl_fa_delete_session (am, sw_if_index, session_index); - count_deleted_sessions++; + count_deleted_sessions++; } } else @@ -1210,22 +1270,9 @@ acl_fa_session_cleaner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (am->fa_current_cleaner_timer_wait_interval < max_timer_wait_interval) am->fa_current_cleaner_timer_wait_interval += cpu_cps * am->fa_cleaner_wait_time_increment; } - - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node.index, - ACL_FA_CLEANER_ERROR_EVENT_CYCLE, 1); - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node.index, - ACL_FA_CLEANER_ERROR_TIMER_RESTARTED, - count_timer_restarted); - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node.index, - ACL_FA_CLEANER_ERROR_DELETED_SESSIONS, - count_deleted_sessions); - vlib_node_increment_counter (vm, - acl_fa_session_cleaner_process_node.index, - ACL_FA_CLEANER_ERROR_ALREADY_DELETED, - count_already_deleted); + am->fa_cleaner_cnt_event_cycles++; + am->fa_cleaner_cnt_deleted_sessions += count_deleted_sessions; + am->fa_cleaner_cnt_already_deleted += count_already_deleted; } /* NOT REACHED */ return 0;