{
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;
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)
{
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);
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)
{
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);
+
}
}
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;
}
}
/* *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 */
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;
{
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)
/* 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);
}
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",
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;
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);
}
}
-
u32 *psid = NULL;
vec_foreach (psid, expired)
{
/* 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
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;