Skip to content

Commit 09d427c

Browse files
authored
Simplify and fix TCP netprobe probe (#690)
* add connect failure metric * simplify tcp probe. use target id for transaction id. * remove header, add some comments * use port based transaction id (via string) for icmp
1 parent c3a3a08 commit 09d427c

File tree

6 files changed

+41
-67
lines changed

6 files changed

+41
-67
lines changed

src/handlers/netprobe/NetProbeStreamHandler.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ void NetProbeStreamHandler::probe_signal_send(pcpp::Packet &payload, TestType ty
7979
}
8080
} else if (type == TestType::TCP) {
8181
if (auto tcp = payload.getLayerOfType<pcpp::TcpLayer>(); tcp != nullptr) {
82-
_metrics->process_netprobe_tcp(static_cast<uint32_t>(tcp->getSrcPort()), true, name, stamp);
82+
_metrics->process_netprobe_tcp(true, name, stamp);
8383
}
8484
}
8585
}
@@ -92,7 +92,7 @@ void NetProbeStreamHandler::probe_signal_recv(pcpp::Packet &payload, TestType ty
9292
}
9393
} else if (type == TestType::TCP) {
9494
if (auto tcp = payload.getLayerOfType<pcpp::TcpLayer>(); tcp != nullptr) {
95-
_metrics->process_netprobe_tcp(static_cast<uint32_t>(tcp->getDstPort()), false, name, stamp);
95+
_metrics->process_netprobe_tcp(false, name, stamp);
9696
}
9797
}
9898
}
@@ -119,6 +119,7 @@ void NetProbeMetricsBucket::specialized_merge(const AbstractMetricsBucket &o, Me
119119
if (group_enabled(group::NetProbeMetrics::Counters)) {
120120
_targets_metrics[targetId]->attempts += target.second->attempts;
121121
_targets_metrics[targetId]->successes += target.second->successes;
122+
_targets_metrics[targetId]->connect_failures += target.second->connect_failures;
122123
_targets_metrics[targetId]->dns_failures += target.second->dns_failures;
123124
_targets_metrics[targetId]->timed_out += target.second->timed_out;
124125
}
@@ -143,6 +144,7 @@ void NetProbeMetricsBucket::to_prometheus(std::stringstream &out, Metric::LabelM
143144
if (group_enabled(group::NetProbeMetrics::Counters)) {
144145
target.second->attempts.to_prometheus(out, target_labels);
145146
target.second->successes.to_prometheus(out, target_labels);
147+
target.second->connect_failures.to_prometheus(out, target_labels);
146148
target.second->dns_failures.to_prometheus(out, target_labels);
147149
target.second->timed_out.to_prometheus(out, target_labels);
148150
}
@@ -198,6 +200,7 @@ void NetProbeMetricsBucket::to_opentelemetry(metrics::v1::ScopeMetrics &scope, t
198200
if (group_enabled(group::NetProbeMetrics::Counters)) {
199201
target.second->attempts.to_opentelemetry(scope, start_ts, end_ts, target_labels);
200202
target.second->successes.to_opentelemetry(scope, start_ts, end_ts, target_labels);
203+
target.second->connect_failures.to_opentelemetry(scope, start_ts, end_ts, target_labels);
201204
target.second->dns_failures.to_opentelemetry(scope, start_ts, end_ts, target_labels);
202205
target.second->timed_out.to_opentelemetry(scope, start_ts, end_ts, target_labels);
203206
}
@@ -252,6 +255,7 @@ void NetProbeMetricsBucket::to_json(json &j) const
252255
if (group_enabled(group::NetProbeMetrics::Counters)) {
253256
target.second->attempts.to_json(j["targets"][targetId]);
254257
target.second->successes.to_json(j["targets"][targetId]);
258+
target.second->connect_failures.to_json(j["targets"][targetId]);
255259
target.second->dns_failures.to_json(j["targets"][targetId]);
256260
target.second->timed_out.to_json(j["targets"][targetId]);
257261
}
@@ -311,9 +315,12 @@ void NetProbeMetricsBucket::process_failure(ErrorType error, const std::string &
311315
break;
312316
case ErrorType::Timeout:
313317
++_targets_metrics[target]->timed_out;
318+
break;
314319
case ErrorType::SocketError:
315320
case ErrorType::InvalidIp:
316-
case ErrorType::ConnectionFailure:
321+
case ErrorType::ConnectFailure:
322+
++_targets_metrics[target]->connect_failures;
323+
break;
317324
default:
318325
break;
319326
}
@@ -374,12 +381,14 @@ void NetProbeMetricsManager::process_netprobe_icmp(pcpp::IcmpLayer *layer, const
374381

375382
if (layer->getMessageType() == pcpp::ICMP_ECHO_REQUEST) {
376383
if (auto request = layer->getEchoRequestData(); request != nullptr) {
377-
_request_reply_manager->start_transaction((static_cast<uint32_t>(request->header->id) << 16) | request->header->sequence, {{stamp, {0, 0}}, target});
384+
auto ping_id = (static_cast<uint32_t>(request->header->id) << 16) | request->header->sequence;
385+
_request_reply_manager->start_transaction(std::to_string(ping_id), {{stamp, {0, 0}}, target});
378386
}
379387
live_bucket()->process_attempts(_deep_sampling_now, target);
380388
} else if (layer->getMessageType() == pcpp::ICMP_ECHO_REPLY) {
381389
if (auto reply = layer->getEchoReplyData(); reply != nullptr) {
382-
auto xact = _request_reply_manager->maybe_end_transaction((static_cast<uint32_t>(reply->header->id) << 16) | reply->header->sequence, stamp);
390+
auto ping_id = (static_cast<uint32_t>(reply->header->id) << 16) | reply->header->sequence;
391+
auto xact = _request_reply_manager->maybe_end_transaction(std::to_string(ping_id), stamp);
383392
if (xact.first == Result::Valid) {
384393
live_bucket()->new_transaction(_deep_sampling_now, xact.second);
385394
} else if (xact.first == Result::TimedOut) {
@@ -389,16 +398,16 @@ void NetProbeMetricsManager::process_netprobe_icmp(pcpp::IcmpLayer *layer, const
389398
}
390399
}
391400

392-
void NetProbeMetricsManager::process_netprobe_tcp(uint32_t port, bool send, const std::string &target, timespec stamp)
401+
void NetProbeMetricsManager::process_netprobe_tcp(bool send, const std::string &target, timespec stamp)
393402
{
394403
// base event
395404
new_event(stamp);
396405

397406
if (send) {
398-
_request_reply_manager->start_transaction(port, {{stamp, {0, 0}}, target});
407+
_request_reply_manager->start_transaction(target, {{stamp, {0, 0}}, target});
399408
live_bucket()->process_attempts(_deep_sampling_now, target);
400409
} else {
401-
auto xact = _request_reply_manager->maybe_end_transaction(port, stamp);
410+
auto xact = _request_reply_manager->maybe_end_transaction(target, stamp);
402411
if (xact.first == Result::Valid) {
403412
live_bucket()->new_transaction(_deep_sampling_now, xact.second);
404413
} else if (xact.first == Result::TimedOut) {

src/handlers/netprobe/NetProbeStreamHandler.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct Target {
4949
Counter successes;
5050
Counter minimum;
5151
Counter maximum;
52+
Counter connect_failures;
5253
Counter dns_failures;
5354
Counter timed_out;
5455

@@ -59,7 +60,8 @@ struct Target {
5960
, successes(NET_PROBE_SCHEMA, {"successes"}, "Total Net Probe successes")
6061
, minimum(NET_PROBE_SCHEMA, {"response_min_us"}, "Minimum response time measured in the reporting interval")
6162
, maximum(NET_PROBE_SCHEMA, {"response_max_us"}, "Maximum response time measured in the reporting interval")
62-
, dns_failures(NET_PROBE_SCHEMA, {"dns_lookup_failures"}, "Total Net Probe failures when performed DNS lookup")
63+
, connect_failures(NET_PROBE_SCHEMA, {"connect_failures"}, "Total Net Probe failures when performing a TCP socket connection")
64+
, dns_failures(NET_PROBE_SCHEMA, {"dns_lookup_failures"}, "Total Net Probe failures when performing a DNS lookup")
6365
, timed_out(NET_PROBE_SCHEMA, {"packets_timeout"}, "Total Net Probe timeout transactions")
6466
{
6567
}
@@ -98,7 +100,7 @@ class NetProbeMetricsBucket final : public visor::AbstractMetricsBucket
98100

99101
class NetProbeMetricsManager final : public visor::AbstractMetricsManager<NetProbeMetricsBucket>
100102
{
101-
typedef TransactionManager<uint32_t, NetProbeTransaction, std::hash<uint32_t>> NetProbeTransactionManager;
103+
typedef TransactionManager<std::string, NetProbeTransaction, std::hash<std::string>> NetProbeTransactionManager;
102104
std::unique_ptr<NetProbeTransactionManager> _request_reply_manager;
103105

104106
public:
@@ -122,7 +124,7 @@ class NetProbeMetricsManager final : public visor::AbstractMetricsManager<NetPro
122124
void process_filtered(timespec stamp);
123125
void process_failure(ErrorType error, const std::string &target);
124126
void process_netprobe_icmp(pcpp::IcmpLayer *layer, const std::string &target, timespec stamp);
125-
void process_netprobe_tcp(uint32_t port, bool send, const std::string &target, timespec stamp);
127+
void process_netprobe_tcp(bool send, const std::string &target, timespec stamp);
126128
};
127129

128130
class NetProbeStreamHandler final : public visor::StreamMetricsHandler<NetProbeMetricsManager>

src/inputs/netprobe/NetProbe.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ enum class ErrorType {
2424
SocketError,
2525
DnsLookupFailure,
2626
InvalidIp,
27-
ConnectionFailure
27+
ConnectFailure
2828
};
2929

3030
enum class TestType {

src/inputs/netprobe/PingProbe.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ bool PingProbe::start(std::shared_ptr<uvw::Loop> io_loop)
184184
throw NetProbeException("PingProbe - unable to initialize AsyncHandle receiver");
185185
}
186186
_recv_handler->on<uvw::AsyncEvent>([this](const auto &, auto &) {
187+
// note this processes received packets across ALL active ping probes (because of the single receiver thread)
188+
// the expectation is that packets which did not originate from this probe will be ignored by the handler attached to this probe,
189+
// since it did not originate from it
187190
for (auto &[packet, stamp] : PingReceiver::recv_packets) {
188191
_recv(packet, TestType::Ping, _name, stamp);
189192
}

src/inputs/netprobe/TcpProbe.cpp

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,44 +31,17 @@ bool TcpProbe::start(std::shared_ptr<uvw::Loop> io_loop)
3131
}
3232

3333
_interval_timer->on<uvw::TimerEvent>([this](const auto &, auto &) {
34-
_internal_sequence = 0;
35-
_timeout_timer = _io_loop->resource<uvw::TimerHandle>();
36-
if (!_timeout_timer) {
37-
throw NetProbeException("Netprobe - unable to initialize timeout TimerHandle");
38-
}
39-
40-
_timeout_timer->on<uvw::TimerEvent>([this](const auto &, auto &) {
41-
_internal_sequence = _config.packets_per_test;
42-
_fail(ErrorType::Timeout, TestType::Ping, _name);
43-
if (_internal_timer) {
44-
_internal_timer->stop();
45-
}
46-
_interval_timer->again();
47-
});
4834

4935
if (!_dns.empty()) {
5036
auto [ip, ipv4] = _resolve_dns();
5137
_ip_str = ip;
5238
_is_ipv4 = ipv4;
5339
if (_ip_str.empty()) {
54-
_fail(ErrorType::DnsLookupFailure, TestType::Ping, _name);
40+
_fail(ErrorType::DnsLookupFailure, TestType::TCP, _name);
5541
return;
5642
}
5743
}
58-
59-
_internal_timer = _io_loop->resource<uvw::TimerHandle>();
60-
_internal_timer->on<uvw::TimerEvent>([this](const auto &, auto &) {
61-
if (_internal_sequence < _config.packets_per_test) {
62-
_internal_sequence++;
63-
_timeout_timer->stop();
64-
_timeout_timer->start(uvw::TimerHandle::Time{_config.timeout_msec}, uvw::TimerHandle::Time{0});
65-
_perform_tcp_process();
66-
}
67-
});
68-
_timeout_timer->start(uvw::TimerHandle::Time{_config.timeout_msec}, uvw::TimerHandle::Time{0});
6944
_perform_tcp_process();
70-
_internal_sequence++;
71-
_internal_timer->start(uvw::TimerHandle::Time{_config.packets_interval_msec}, uvw::TimerHandle::Time{_config.packets_interval_msec});
7245
});
7346

7447
_interval_timer->start(uvw::TimerHandle::Time{0}, uvw::TimerHandle::Time{_config.interval_msec});
@@ -80,33 +53,32 @@ void TcpProbe::_perform_tcp_process()
8053
{
8154
_client = _io_loop->resource<uvw::TCPHandle>();
8255
_client->on<uvw::ErrorEvent>([this](const auto &, auto &) {
83-
_fail(ErrorType::ConnectionFailure, TestType::Ping, _name);
56+
_fail(ErrorType::ConnectFailure, TestType::TCP, _name);
8457
});
8558
_client->once<uvw::CloseEvent>([this](const uvw::CloseEvent &, uvw::TCPHandle &) {
86-
timespec stamp;
87-
std::timespec_get(&stamp, TIME_UTC);
88-
pcpp::Packet packet;
89-
auto layer = pcpp::TcpLayer(static_cast<uint16_t>(_port), _client_port);
90-
packet.addLayer(&layer);
91-
_recv(packet, TestType::TCP, _name, stamp);
9259
});
93-
_client->once<uvw::ShutdownEvent>([](const uvw::ShutdownEvent &, uvw::TCPHandle &handle) {
60+
_client->once<uvw::ShutdownEvent>([this](const uvw::ShutdownEvent &, uvw::TCPHandle &handle) {
9461
handle.close();
9562
});
9663
_client->once<uvw::ConnectEvent>([this](const uvw::ConnectEvent &, uvw::TCPHandle &handle) {
9764
timespec stamp;
9865
std::timespec_get(&stamp, TIME_UTC);
99-
_client_port = static_cast<uint16_t>(handle.sock().port);
10066
pcpp::Packet packet;
101-
auto layer = pcpp::TcpLayer(_client_port, static_cast<uint16_t>(_port));
67+
auto layer = pcpp::TcpLayer(0, static_cast<uint16_t>(_dst_port));
10268
packet.addLayer(&layer);
103-
_send(packet, TestType::TCP, _name, stamp);
69+
_recv(packet, TestType::TCP, _name, stamp);
10470
handle.shutdown();
10571
});
72+
timespec stamp;
73+
std::timespec_get(&stamp, TIME_UTC);
74+
pcpp::Packet packet;
75+
auto layer = pcpp::TcpLayer(0, static_cast<uint16_t>(_dst_port));
76+
packet.addLayer(&layer);
77+
_send(packet, TestType::TCP, _name, stamp);
10678
if (_is_ipv4) {
107-
_client->connect<uvw::TCPHandle::IPv4>(_ip_str, _port);
79+
_client->connect<uvw::TCPHandle::IPv4>(_ip_str, _dst_port);
10880
} else {
109-
_client->connect<uvw::TCPHandle::IPv6>(_ip_str, _port);
81+
_client->connect<uvw::TCPHandle::IPv6>(_ip_str, _dst_port);
11082
}
11183
}
11284

src/inputs/netprobe/TcpProbe.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,13 @@
1111

1212
namespace visor::input::netprobe {
1313

14-
/**
15-
* @class PingProbe
16-
* @brief PingProbe class used for sending ICMP Echo Requests.
17-
*
18-
* This class is created for each specified target. However, it reuses a shared socket per thread (per UV_LOOP).
19-
* I.e. each unique NetProbeInputStream with Ping Type will have a socket to send ICMP Echo Request.
20-
*/
2114
class TcpProbe final : public NetProbe
2215
{
23-
uint32_t _port;
24-
uint16_t _client_port;
16+
uint32_t _dst_port;
2517
bool _init{false};
2618
bool _is_ipv4{false};
27-
uint16_t _internal_sequence{0};
2819
std::string _ip_str;
2920
std::shared_ptr<uvw::TimerHandle> _interval_timer;
30-
std::shared_ptr<uvw::TimerHandle> _internal_timer;
31-
std::shared_ptr<uvw::TimerHandle> _timeout_timer;
3221

3322
std::shared_ptr<uvw::TCPHandle> _client;
3423

@@ -37,8 +26,7 @@ class TcpProbe final : public NetProbe
3726
public:
3827
TcpProbe(uint16_t id, const std::string &name, const pcpp::IPAddress &ip, const std::string &dns, uint32_t port)
3928
: NetProbe(id, name, ip, dns)
40-
, _port(port)
41-
, _client_port(0){};
29+
, _dst_port(port) {};
4230
~TcpProbe() = default;
4331
bool start(std::shared_ptr<uvw::Loop> io_loop) override;
4432
bool stop() override;

0 commit comments

Comments
 (0)