example/ex_netcompact.cc (111 lines of code) (raw):

// SPDX-License-Identifier: Apache-2.0 // Copyright 2014 Network Geographics /** @file Example tool to compact networks. Input is a file with addresses. Each line should be an address, an address range, or a network in CIDR format. 4441:34F8:1E40:1EF:0:0:A0:0/108 192.168.12.1 10.0.23.0-10.0.14.255 The output is the same set of addresses in as few networks as possible. */ #include <unordered_set> #include <iostream> #include <fstream> #include "swoc/TextView.h" #include "swoc/swoc_ip.h" #include "swoc/bwf_ip.h" #include "swoc/bwf_std.h" #include "swoc/bwf_std.h" #include "swoc/swoc_file.h" using namespace std::literals; using namespace swoc::literals; using swoc::TextView; using swoc::IPRange; /// Type for temporary buffer writer output. using W = swoc::LocalBufferWriter<512>; /// IPSpace for mapping address. Treating it as a set so use a no-data payload. using Space = swoc::IPSpace<std::monostate>; void post_processing_performance_test(Space &space); /// Process the @a content of a file in to @a space. unsigned process(Space &space, TextView content) { int line_no = 0; /// Track for error reporting. unsigned n_ranges = 0; // For each line in @a content while (content) { TextView line = content.take_prefix_at('\n').trim_if(&isspace); ++line_no; // Allow empty lines and '#' comments without error. if (line.empty() || '#' == *line) { continue; } // Get the range, make sure it's a valid range. IPRange range{line}; if (range.empty()) { std::cerr << W().print("Invalid range '{}' on line {}\n", line, line_no); continue; } ++n_ranges; space.mark(range, std::monostate{}); } return n_ranges; } int main(int argc, char *argv[]) { Space space; if (argc < 2) { std::cerr << W().print("Input file name required.\n"); exit(1); } auto t0 = std::chrono::system_clock::now(); // timing // Load the file. swoc::file::path path{argv[1]}; std::error_code ec; std::string content = swoc::file::load(path, ec); if (ec) { std::cerr << W().print(R"(Failed to open file "{}" - {}\n)", path, ec); exit(1); } // Paint the IPSpace. auto n_ranges = process(space, content); // Dump the results. unsigned n_nets = 0; for (auto &&[range, payload] : space) { for (auto &&net : range.networks()) { ++n_nets; std::cout << W().print("{}\n", net); } } auto delta = std::chrono::system_clock::now() - t0; std::cerr << W().print("{} ranges in, {} ranges condensed, {} networks out in {} ms\n", n_ranges, space.count(), n_nets, std::chrono::duration_cast<std::chrono::milliseconds>(delta).count()); post_processing_performance_test(space); return 0; } void post_processing_performance_test(Space &space) { using swoc::IP4Addr; using swoc::IP6Addr; std::vector<IP4Addr> a4; std::vector<IP6Addr> a6; for (auto &&[r, p] : space) { if (r.is_ip4()) { IP4Addr a = r.min().ip4(); a4.push_back(a); a4.push_back(--IP4Addr(a)); a4.push_back(++IP4Addr(a)); a = r.max().ip4(); a4.push_back(a); a4.push_back(--IP4Addr(a)); a4.push_back(++IP4Addr(a)); } else if (r.is_ip6()) { IP6Addr a = r.min().ip6(); a6.push_back(a); a6.push_back(--IP6Addr(a)); a6.push_back(++IP6Addr(a)); a = r.max().ip6(); a6.push_back(a); a6.push_back(--IP6Addr(a)); a6.push_back(++IP6Addr(a)); } } if (!a4.empty()) { auto t0 = std::chrono::system_clock::now(); for (auto const &addr : a4) { [[maybe_unused]] auto spot = space.find(addr); } auto delta = std::chrono::system_clock::now() - t0; std::cout << W().print("IPv4 time - {} addresses, {} ns total, {} ns per lookup\n", a4.size(), delta.count(), delta.count() / a4.size()); } if (!a6.empty()) { auto t0 = std::chrono::system_clock::now(); for (auto const &addr : a6) { [[maybe_unused]] auto spot = space.find(addr); } auto delta = std::chrono::system_clock::now() - t0; std::cout << W().print("IPv6 time - {} addresses, {} ns total, {} ns per lookup\n", a6.size(), delta.count(), delta.count() / a6.size()); } }