RunState: Implement forward_network_time_if_applicable()

Add a central place where the decision when it's okay to update network time
to the current time (wallclock) is. It checks for pseudo_realtime and packet
source existence as well as packet source idleness.

A new const &redef allows to completely disable forwarding of network time.
This commit is contained in:
Arne Welzel 2023-03-15 15:03:17 +01:00
parent eefa0150b9
commit d4e31e7d2b
4 changed files with 80 additions and 13 deletions

View file

@ -161,6 +161,32 @@ type PacketSource: record {
netmask: count; netmask: count;
}; };
## If a packet source does not yield packets for this amount of time,
## it is considered idle. When a packet source is found to be idle,
## Zeek will update network_time to current time in order for timer expiration
## to function. A packet source queueing up packets and not yielding them for
## longer than this interval without yielding any packets will provoke
## not-very-well-defined timer behavior.
##
## On Zeek workers with low packet rates, timer expiration may be delayed
## by this many milliseconds after the last packet has been received.
const packet_source_inactivity_timeout = 100msec &redef;
## Whether Zeek will forward network_time to the current time upon
## observing an idle packet source (or no configured packet source).
##
## Only set this to *F* if you really know what you're doing. Setting this to
## *F* on non-worker systems causes :zeek:see:`network_time` to be stuck
## at 0.0 and timer expiration will be non-functional.
##
## The main purpose of this option is to yield control over network time
## to plugins or scripts via broker or other non-timer events.
##
## .. zeek:see:: network_time set_network_time packet_source_inactivity_timeout
##
const allow_network_time_forward = T &redef;
## A connection's transport-layer protocol. Note that Zeek uses the term ## A connection's transport-layer protocol. Note that Zeek uses the term
## "connection" broadly, using flow semantics for ICMP and UDP. ## "connection" broadly, using flow semantics for ICMP and UDP.
type transport_proto: enum { type transport_proto: enum {

View file

@ -137,6 +137,44 @@ void update_network_time(double new_network_time)
PLUGIN_HOOK_VOID(HOOK_UPDATE_NETWORK_TIME, HookUpdateNetworkTime(new_network_time)); PLUGIN_HOOK_VOID(HOOK_UPDATE_NETWORK_TIME, HookUpdateNetworkTime(new_network_time));
} }
// Logic to decide when updating network_time is acceptable:
static bool should_forward_network_time()
{
// In pseudo_realtime mode, always update time once
// we've dispatched and processed the first packet.
// run_state::detail::first_timestamp is currently set
// in PktSrc::ExtractNextPacketInternal()
if ( pseudo_realtime != 0.0 && run_state::detail::first_timestamp != 0.0 )
return true;
if ( iosource::PktSrc* ps = iosource_mgr->GetPktSrc() )
{
// Offline packet sources always control network time
// unless we're running pseudo_realtime, see above.
if ( ! ps->IsLive() )
return false;
if ( ! ps->HasBeenIdleFor(BifConst::packet_source_inactivity_timeout) )
return false;
}
// We determined that we don't have a packet source, or it is idle.
// Unless it has been disabled, network_time will now be moved forward.
return BifConst::allow_network_time_forward;
}
static void forward_network_time_if_applicable()
{
if ( ! should_forward_network_time() )
return;
double now = util::current_time(true);
if ( now > network_time )
update_network_time(now);
return;
}
void init_run(const std::optional<std::string>& interface, void init_run(const std::optional<std::string>& interface,
const std::optional<std::string>& pcap_input_file, const std::optional<std::string>& pcap_input_file,
const std::optional<std::string>& pcap_output_file, bool do_watchdog) const std::optional<std::string>& pcap_output_file, bool do_watchdog)
@ -319,21 +357,21 @@ void run_loop()
// date on timers and events. Because we only // date on timers and events. Because we only
// have timers as sources, going to sleep here // have timers as sources, going to sleep here
// doesn't risk blocking on other inputs. // doesn't risk blocking on other inputs.
update_network_time(util::current_time()); //
// TBD: Is this actually still relevant given that the TimerMgr
// is an IO source now? It'll be processed once its
// GetNextTimeout() yields 0 and before that there's nothing
// to expire anyway.
forward_network_time_if_applicable();
expire_timers(); expire_timers();
// Prevent another forward_network_time_if_applicable() below
// even if time wasn't actually updated.
time_updated = true;
} }
// Ensure that the time gets updated every pass if we're reading live. if ( ! time_updated )
// This is necessary for e.g. packet sources that don't have a selectable forward_network_time_if_applicable();
// file descriptor. They'll always be ready on a very short timeout, but
// won't necessarily have a packet to process. In these case, sometimes
// the time won't get updated for a long time and timers don't function
// correctly.
if ( (! time_updated && reading_live) )
{
update_network_time(util::current_time());
expire_timers();
}
event_mgr.Drain(); event_mgr.Drain();

View file

@ -2,6 +2,8 @@
##! internally. Documentation and default values for the scripting-layer ##! internally. Documentation and default values for the scripting-layer
##! variables themselves are found in :doc:`/scripts/base/init-bare.zeek`. ##! variables themselves are found in :doc:`/scripts/base/init-bare.zeek`.
const packet_source_inactivity_timeout: interval;
const allow_network_time_forward: bool;
const ignore_keep_alive_rexmit: bool; const ignore_keep_alive_rexmit: bool;
const skip_http_data: bool; const skip_http_data: bool;
const use_conn_size_analyzer: bool; const use_conn_size_analyzer: bool;

View file

@ -1036,7 +1036,8 @@ SetupResult setup(int argc, char** argv, Options* zopts)
segment_logger = profiling_logger; segment_logger = profiling_logger;
} }
if ( ! run_state::reading_live && ! run_state::reading_traces ) if ( ! run_state::reading_live && ! run_state::reading_traces &&
id::find_const("allow_network_time_forward")->AsBool() )
// Set up network_time to track real-time, since // Set up network_time to track real-time, since
// we don't have any other source for it. // we don't have any other source for it.
run_state::detail::update_network_time(util::current_time()); run_state::detail::update_network_time(util::current_time());