|
19 | 19 |
|
20 | 20 | namespace visor::handler::flow {
|
21 | 21 |
|
| 22 | +template <typename Out> |
| 23 | +static void split(const std::string &s, char delim, Out result) |
| 24 | +{ |
| 25 | + std::stringstream ss; |
| 26 | + ss.str(s); |
| 27 | + std::string item; |
| 28 | + while (std::getline(ss, item, delim)) { |
| 29 | + *(result++) = item; |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +static std::vector<std::string> split(const std::string &s, char delim) |
| 34 | +{ |
| 35 | + std::vector<std::string> elems; |
| 36 | + split(s, delim, std::back_inserter(elems)); |
| 37 | + return elems; |
| 38 | +} |
| 39 | + |
22 | 40 | FlowStreamHandler::FlowStreamHandler(const std::string &name, InputEventProxy *proxy, const Configurable *window_config)
|
23 | 41 | : visor::StreamMetricsHandler<FlowMetricsManager>(name, window_config)
|
24 | 42 | , _sample_rate_scaling(true)
|
@@ -47,6 +65,54 @@ void FlowStreamHandler::start()
|
47 | 65 |
|
48 | 66 | process_groups(_group_defs);
|
49 | 67 |
|
| 68 | + // Setup Configs |
| 69 | + if (config_exists("recorded_stream")) { |
| 70 | + _metrics->set_recorded_stream(); |
| 71 | + } |
| 72 | + |
| 73 | + EnrichMap enrich_data; |
| 74 | + if (config_exists("device_map")) { |
| 75 | + for (const auto &device_info : config_get<StringList>("device_map")) { |
| 76 | + std::vector<std::string> data = split(device_info, ','); |
| 77 | + if (data.size() < 2) { |
| 78 | + // should at least contain device name and ip |
| 79 | + continue; |
| 80 | + } |
| 81 | + DeviceEnrich *device{nullptr}; |
| 82 | + if (auto it = enrich_data.find(data[1]); it != enrich_data.end()) { |
| 83 | + device = &it->second; |
| 84 | + } else { |
| 85 | + enrich_data[data[1]] = DeviceEnrich{data[0], {}}; |
| 86 | + device = &enrich_data[data[1]]; |
| 87 | + } |
| 88 | + if (data.size() < 4) { |
| 89 | + // should have interface information |
| 90 | + continue; |
| 91 | + } |
| 92 | + auto if_index = static_cast<uint32_t>(std::stol(data[3])); |
| 93 | + if (auto it = device->interfaces.find(if_index); it == device->interfaces.end()) { |
| 94 | + if (data.size() > 4) { |
| 95 | + device->interfaces[if_index] = InterfaceEnrich{data[2], data[4]}; |
| 96 | + } else { |
| 97 | + device->interfaces[if_index] = InterfaceEnrich{data[2], std::string()}; |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + std::unordered_map<std::string, std::string> concat_if; |
| 104 | + if (config_exists("first_filter_if_as_label") && config_get<bool>("first_filter_if_as_label") && config_exists("only_interfaces")) { |
| 105 | + concat_if["default"] = config_get<StringList>("only_interfaces")[0]; |
| 106 | + auto interface = static_cast<uint32_t>(std::stoul(config_get<StringList>("only_interfaces")[0])); |
| 107 | + for (const auto &data : enrich_data) { |
| 108 | + auto it = data.second.interfaces.find(interface); |
| 109 | + if (it != data.second.interfaces.end()) { |
| 110 | + concat_if[data.first] = it->second.name; |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | + _metrics->set_enrich_data(std::move(concat_if), std::move(enrich_data)); |
| 115 | + |
50 | 116 | // Setup Filters
|
51 | 117 | if (config_exists("only_ips")) {
|
52 | 118 | _parse_host_specs(config_get<StringList>("only_ips"));
|
@@ -80,10 +146,6 @@ void FlowStreamHandler::start()
|
80 | 146 | _sample_rate_scaling = false;
|
81 | 147 | }
|
82 | 148 |
|
83 |
| - if (config_exists("recorded_stream")) { |
84 |
| - _metrics->set_recorded_stream(); |
85 |
| - } |
86 |
| - |
87 | 149 | if (_flow_proxy) {
|
88 | 150 | _sflow_connection = _flow_proxy->sflow_signal.connect(&FlowStreamHandler::process_sflow_cb, this);
|
89 | 151 | _netflow_connection = _flow_proxy->netflow_signal.connect(&FlowStreamHandler::process_netflow_cb, this);
|
@@ -471,7 +533,6 @@ void FlowMetricsBucket::specialized_merge(const AbstractMetricsBucket &o, Metric
|
471 | 533 |
|
472 | 534 | for (const auto &device : other._devices_metrics) {
|
473 | 535 | const auto &deviceId = device.first;
|
474 |
| - const auto &device_data = device.second; |
475 | 536 |
|
476 | 537 | if (group_enabled(group::FlowMetrics::Counters)) {
|
477 | 538 | _devices_metrics[deviceId]->counters.UDP += device.second->counters.UDP;
|
@@ -542,7 +603,22 @@ void FlowMetricsBucket::to_prometheus(std::stringstream &out, Metric::LabelMap a
|
542 | 603 |
|
543 | 604 | for (const auto &device : _devices_metrics) {
|
544 | 605 | auto device_labels = add_labels;
|
545 |
| - device_labels["device"] = device.first; |
| 606 | + auto deviceId = device.first; |
| 607 | + DeviceEnrich *dev{nullptr}; |
| 608 | + if (_enrich_data) { |
| 609 | + if (auto it = _enrich_data->find(deviceId); it != _enrich_data->end()) { |
| 610 | + dev = &it->second; |
| 611 | + deviceId = it->second.name; |
| 612 | + } |
| 613 | + } |
| 614 | + device_labels["device"] = deviceId; |
| 615 | + if (_concat_if) { |
| 616 | + if (auto it = _concat_if->find(device.first); (it != _concat_if->end()) && !it->second.empty()) { |
| 617 | + device_labels["device_interface"] = deviceId + "|" + it->second; |
| 618 | + } else { |
| 619 | + device_labels["device_interface"] = deviceId + "|" + _concat_if->at("default"); |
| 620 | + } |
| 621 | + } |
546 | 622 |
|
547 | 623 | if (group_enabled(group::FlowMetrics::Counters)) {
|
548 | 624 | device.second->counters.UDP.to_prometheus(out, device_labels);
|
@@ -574,8 +650,22 @@ void FlowMetricsBucket::to_prometheus(std::stringstream &out, Metric::LabelMap a
|
574 | 650 | if (group_enabled(group::FlowMetrics::Conversations)) {
|
575 | 651 | device.second->topByBytes.topConversations.to_prometheus(out, device_labels);
|
576 | 652 | }
|
577 |
| - device.second->topByBytes.topInIfIndex.to_prometheus(out, device_labels, [](const uint32_t &val) { return std::to_string(val); }); |
578 |
| - device.second->topByBytes.topOutIfIndex.to_prometheus(out, device_labels, [](const uint32_t &val) { return std::to_string(val); }); |
| 653 | + device.second->topByBytes.topInIfIndex.to_prometheus(out, device_labels, [dev](const uint32_t &val) { |
| 654 | + if (dev) { |
| 655 | + if (auto it = dev->interfaces.find(val); it != dev->interfaces.end()) { |
| 656 | + return it->second.name; |
| 657 | + } |
| 658 | + } |
| 659 | + return std::to_string(val); |
| 660 | + }); |
| 661 | + device.second->topByBytes.topOutIfIndex.to_prometheus(out, device_labels, [dev](const uint32_t &val) { |
| 662 | + if (dev) { |
| 663 | + if (auto it = dev->interfaces.find(val); it != dev->interfaces.end()) { |
| 664 | + return it->second.name; |
| 665 | + } |
| 666 | + } |
| 667 | + return std::to_string(val); |
| 668 | + }); |
579 | 669 | if (group_enabled(group::FlowMetrics::TopGeo)) {
|
580 | 670 | device.second->topByBytes.topGeoLoc.to_prometheus(out, device_labels);
|
581 | 671 | device.second->topByBytes.topASN.to_prometheus(out, device_labels);
|
@@ -613,6 +703,21 @@ void FlowMetricsBucket::to_json(json &j) const
|
613 | 703 |
|
614 | 704 | for (const auto &device : _devices_metrics) {
|
615 | 705 | auto deviceId = device.first;
|
| 706 | + DeviceEnrich *dev{nullptr}; |
| 707 | + if (_enrich_data) { |
| 708 | + auto it = _enrich_data->find(deviceId); |
| 709 | + if (it != _enrich_data->end()) { |
| 710 | + dev = &it->second; |
| 711 | + deviceId = it->second.name; |
| 712 | + } |
| 713 | + } |
| 714 | + if (_concat_if) { |
| 715 | + if (auto it = _concat_if->find(device.first); (it != _concat_if->end()) && !it->second.empty()) { |
| 716 | + deviceId += "|" + it->second; |
| 717 | + } else { |
| 718 | + deviceId += "|" + _concat_if->at("default"); |
| 719 | + } |
| 720 | + } |
616 | 721 |
|
617 | 722 | if (group_enabled(group::FlowMetrics::Counters)) {
|
618 | 723 | device.second->counters.UDP.to_json(j["devices"][deviceId]);
|
@@ -644,8 +749,22 @@ void FlowMetricsBucket::to_json(json &j) const
|
644 | 749 | if (group_enabled(group::FlowMetrics::Conversations)) {
|
645 | 750 | device.second->topByBytes.topConversations.to_json(j["devices"][deviceId]);
|
646 | 751 | }
|
647 |
| - device.second->topByBytes.topInIfIndex.to_json(j["devices"][deviceId], [](const uint32_t &val) { return std::to_string(val); }); |
648 |
| - device.second->topByBytes.topOutIfIndex.to_json(j["devices"][deviceId], [](const uint32_t &val) { return std::to_string(val); }); |
| 752 | + device.second->topByBytes.topInIfIndex.to_json(j["devices"][deviceId], [dev](const uint32_t &val) { |
| 753 | + if (dev) { |
| 754 | + if (auto it = dev->interfaces.find(val); it != dev->interfaces.end()) { |
| 755 | + return it->second.name; |
| 756 | + } |
| 757 | + } |
| 758 | + return std::to_string(val); |
| 759 | + }); |
| 760 | + device.second->topByBytes.topOutIfIndex.to_json(j["devices"][deviceId], [dev](const uint32_t &val) { |
| 761 | + if (dev) { |
| 762 | + if (auto it = dev->interfaces.find(val); it != dev->interfaces.end()) { |
| 763 | + return it->second.name; |
| 764 | + } |
| 765 | + } |
| 766 | + return std::to_string(val); |
| 767 | + }); |
649 | 768 | if (group_enabled(group::FlowMetrics::TopGeo)) {
|
650 | 769 | device.second->topByBytes.topGeoLoc.to_json(j["devices"][deviceId]);
|
651 | 770 | device.second->topByBytes.topASN.to_json(j["devices"][deviceId]);
|
|
0 commit comments