mirror of
https://github.com/pavel-odintsov/fastnetmon.git
synced 2024-09-21 18:37:13 +00:00
Added extensive documentation about template update logic
This commit is contained in:
parent
fa71ec7c59
commit
b7aa639548
@ -603,6 +603,20 @@ std::vector<system_counter_t> get_netflow_stats() {
|
||||
return system_counter;
|
||||
}
|
||||
|
||||
// Returns fancy name of protocol version
|
||||
std::string get_netflow_protocol_version_as_string(const netflow_protocol_version_t& netflow_protocol_version) {
|
||||
std::string protocol_name = "unknown";
|
||||
|
||||
if (netflow_protocol_version == netflow_protocol_version_t::netflow_v9) {
|
||||
protocol_name = "Netflow v9";
|
||||
} else if (netflow_protocol_version == netflow_protocol_version_t::ipfix) {
|
||||
protocol_name = "IPFIX";
|
||||
}
|
||||
|
||||
return protocol_name;
|
||||
}
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
void add_update_peer_template(const netflow_protocol_version_t& netflow_version,
|
||||
std::map<std::string, std::map<uint32_t, template_t>>& table_for_add,
|
||||
@ -727,84 +741,141 @@ void override_packet_fields_from_nested_packet(simple_packet_t& packet, const si
|
||||
std::copy(std::begin(nested_packet.destination_mac), std::end(nested_packet.destination_mac), std::begin(packet.destination_mac));
|
||||
}
|
||||
|
||||
|
||||
// Wrapper functions
|
||||
template_t* peer_nf9_find_template(uint32_t source_id, uint32_t template_id, std::string client_addres_in_string_format) {
|
||||
return peer_find_template(global_netflow9_templates, source_id, template_id, client_addres_in_string_format);
|
||||
}
|
||||
|
||||
template_t* peer_nf10_find_template(uint32_t source_id, uint32_t template_id, std::string client_addres_in_string_format) {
|
||||
return peer_find_template(global_ipfix_templates, source_id, template_id, client_addres_in_string_format);
|
||||
}
|
||||
|
||||
void add_update_peer_template(const netflow_protocol_version_t& netflow_version,
|
||||
void add_update_peer_template(
|
||||
const netflow_protocol_version_t& netflow_protocol_version,
|
||||
std::map<std::string, std::map<uint32_t, template_t>>& table_for_add,
|
||||
uint32_t source_id,
|
||||
uint32_t template_id,
|
||||
const std::string& client_addres_in_string_format,
|
||||
const std::string& client_address_in_string_format,
|
||||
const template_t& field_template,
|
||||
bool& updated,
|
||||
bool& updated_existing_template) {
|
||||
|
||||
std::string key = client_addres_in_string_format + "_" + std::to_string(source_id);
|
||||
std::string key = client_address_in_string_format + "_" + std::to_string(source_id);
|
||||
|
||||
// logger<< log4cpp::Priority::INFO<<"It's new option template
|
||||
// "<<template_id<<" for host:
|
||||
// "<<client_addres_in_string_format
|
||||
// <<" with source id: "<<source_id;
|
||||
if (logger.getPriority() == log4cpp::Priority::DEBUG) {
|
||||
logger << log4cpp::Priority::DEBUG << "Received " << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template with id " << template_id << " from host " << client_address_in_string_format
|
||||
<< " source id: " << source_id;
|
||||
}
|
||||
|
||||
auto itr = table_for_add.find(key);
|
||||
|
||||
if (itr != table_for_add.end()) {
|
||||
// We have information block about this agent
|
||||
|
||||
// Try to find actual template id here
|
||||
if (itr->second.count(template_id) > 0) {
|
||||
// logger<< log4cpp::Priority::INFO<<"We already have information about
|
||||
// this template
|
||||
// with id:"
|
||||
// <<template_id<<" for host: "<<client_addres_in_string_format;
|
||||
|
||||
// Should I track timestamp here and drop old templates after some time?
|
||||
if (itr->second[template_id] != field_template) {
|
||||
itr->second[template_id] = field_template;
|
||||
|
||||
updated = true;
|
||||
} else {
|
||||
template_update_attempts_with_same_template_data++;
|
||||
}
|
||||
} else {
|
||||
// logger<< log4cpp::Priority::INFO<<"It's new option template
|
||||
// "<<template_id<<" for
|
||||
// host: "<<client_addres_in_string_format;
|
||||
itr->second[template_id] = field_template;
|
||||
updated = true;
|
||||
}
|
||||
} else {
|
||||
// We do not have any information about this Netflow agent
|
||||
if (itr == table_for_add.end()) {
|
||||
std::map<uint32_t, template_t> temp_template_storage;
|
||||
temp_template_storage[template_id] = field_template;
|
||||
|
||||
table_for_add[key] = temp_template_storage;
|
||||
updated = true;
|
||||
|
||||
if (logger.getPriority() == log4cpp::Priority::DEBUG) {
|
||||
logger << log4cpp::Priority::DEBUG << "We had no "
|
||||
<< get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " templates for source " << key;
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "Added " << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template with ID " << template_id << " for " << key;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We have information about this agent
|
||||
|
||||
// Try to find actual template id here
|
||||
if (itr->second.count(template_id) == 0) {
|
||||
|
||||
if (logger.getPriority() == log4cpp::Priority::DEBUG) {
|
||||
logger << log4cpp::Priority::DEBUG << "We had no information about "
|
||||
<< get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template with ID " << template_id << " for " << key;
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "Added " << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template with ID " << template_id << " for " << key;
|
||||
}
|
||||
|
||||
itr->second[template_id] = field_template;
|
||||
updated = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Should I track timestamp here and drop old templates after some time?
|
||||
if (itr->second[template_id] != field_template) {
|
||||
//
|
||||
// We can see that template definition actually changed
|
||||
//
|
||||
// In case of IPFIX this is clear protocol violation:
|
||||
// https://datatracker.ietf.org/doc/html/rfc7011#section-8.1
|
||||
//
|
||||
|
||||
//
|
||||
// If a Collecting Process receives a new Template Record or Options
|
||||
// Template Record for an already-allocated Template ID, and that
|
||||
// Template or Options Template is different from the already-received
|
||||
// Template or Options Template, this indicates a malfunctioning or
|
||||
// improperly implemented Exporting Process. The continued receipt and
|
||||
// unambiguous interpretation of Data Records for this Template ID are
|
||||
// no longer possible, and the Collecting Process SHOULD log the error.
|
||||
// Further Collecting Process actions are out of scope for this
|
||||
// specification.
|
||||
//
|
||||
|
||||
//
|
||||
// We cannot follow RFC recommendation for IPFIX as it will break our on disk template caching.
|
||||
// I.e. we may have template with specific list of fields in cache
|
||||
// Then after firmware upgrade vendor changes list of fields but does not change template id
|
||||
// We have to accept new one and update to be able to decode data
|
||||
//
|
||||
|
||||
//
|
||||
// Netflow v9 explicitly prohibits template content updates: https://www.ietf.org/rfc/rfc3954.txt
|
||||
//
|
||||
// A newly created Template record is assigned an unused Template ID
|
||||
// from the Exporter. If the template configuration is changed, the
|
||||
// current Template ID is abandoned and SHOULD NOT be reused until the
|
||||
// NetFlow process or Exporter restarts.
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
// But in same time Netflow v9 RFC allows template update for collector and that's exactly what we do:
|
||||
//
|
||||
// If a Collector should receive a new definition for an already existing Template ID, it MUST discard
|
||||
// the previous template definition and use the new one.
|
||||
//
|
||||
|
||||
// On debug level we have to print templates
|
||||
if (logger.getPriority() == log4cpp::Priority::DEBUG) {
|
||||
logger << log4cpp::Priority::DEBUG << "Old " << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<<" template: " << print_template(itr->second[template_id]);
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "New " << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<<" template: " << print_template(field_template);
|
||||
}
|
||||
|
||||
// We use ERROR level as this behavior is definitely not a common and must be carefully investigated
|
||||
logger << log4cpp::Priority::ERROR << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template " << template_id << " was updated for " << key;
|
||||
|
||||
// Warn user that something bad going on
|
||||
logger << log4cpp::Priority::ERROR << get_netflow_protocol_version_as_string(netflow_protocol_version)
|
||||
<< " template update may be sign of RFC violation by vendor and if you observe this behaviour please reach support@fastnetmon.com and share information about your equipment and firmware versions";
|
||||
|
||||
|
||||
itr->second[template_id] = field_template;
|
||||
|
||||
// We need to track this case as it's pretty unusual and in some cases it may be very destructive when router does it incorrectly
|
||||
updated_existing_template = true;
|
||||
|
||||
updated = true;
|
||||
} else {
|
||||
template_update_attempts_with_same_template_data++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns fancy name of protocol version
|
||||
std::string get_netflow_protocol_version_as_string(const netflow_protocol_version_t& netflow_protocol_version) {
|
||||
std::string protocol_name = "unknown";
|
||||
|
||||
if (netflow_protocol_version == netflow_protocol_version_t::netflow_v9) {
|
||||
protocol_name = "Netflow v9";
|
||||
} else if (netflow_protocol_version == netflow_protocol_version_t::ipfix) {
|
||||
protocol_name = "IPFIX";
|
||||
}
|
||||
|
||||
return protocol_name;
|
||||
}
|
||||
|
||||
/* Copy an int (possibly shorter than the target) keeping their LSBs aligned */
|
||||
#define BE_COPY(a) memcpy((u_char*)&a + (sizeof(a) - record_length), data, record_length);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user