Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82b0b9e2 authored by chenbruce's avatar chenbruce Committed by Automerger Merge Worker
Browse files

Subsampling DNS event for mDNS am: 52cf009b am: 67e70742 am: d5a56ff6

Original change: https://android-review.googlesource.com/c/platform/packages/modules/DnsResolver/+/1799848

Change-Id: I307b4861f410a46616a114d441f99726ab08aa46
parents b1c374c3 d5a56ff6
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#include <sysutils/SocketClient.h>

#include "DnsResolver.h"
#include "Experiments.h"
#include "NetdPermissions.h"
#include "OperationLimiter.h"
#include "PrivateDnsConfiguration.h"
@@ -305,8 +306,8 @@ void initDnsEvent(NetworkDnsEventReported* event, const android_net_context& net

// Return 0 if the event should not be logged.
// Otherwise, return subsampling_denom
uint32_t getDnsEventSubsamplingRate(int netid, int returnCode) {
    uint32_t subsampling_denom = resolv_cache_get_subsampling_denom(netid, returnCode);
uint32_t getDnsEventSubsamplingRate(int netid, int returnCode, bool isMdns) {
    uint32_t subsampling_denom = resolv_cache_get_subsampling_denom(netid, returnCode, isMdns);
    if (subsampling_denom == 0) return 0;
    // Sample the event with a chance of 1 / denom.
    return (arc4random_uniform(subsampling_denom) == 0) ? subsampling_denom : 0;
@@ -333,7 +334,12 @@ void maybeLogQuery(int eventType, const android_net_context& netContext,
void reportDnsEvent(int eventType, const android_net_context& netContext, int latencyUs,
                    int returnCode, NetworkDnsEventReported& event, const std::string& query_name,
                    const std::vector<std::string>& ip_addrs = {}, int total_ip_addr_count = 0) {
    if (uint32_t rate = getDnsEventSubsamplingRate(netContext.dns_netid, returnCode)) {
    uint32_t rate = (query_name.ends_with(".local") &&
                     android::net::Experiments::getInstance()->getFlag("mdns_resolution", 1))
                            ? getDnsEventSubsamplingRate(netContext.dns_netid, returnCode, true)
                            : getDnsEventSubsamplingRate(netContext.dns_netid, returnCode, false);

    if (rate) {
        const std::string& dnsQueryStats = event.dns_query_events().SerializeAsString();
        stats::BytesField dnsQueryBytesField{dnsQueryStats.c_str(), dnsQueryStats.size()};
        event.set_return_code(static_cast<ReturnCode>(returnCode));
+3 −1
Original line number Diff line number Diff line
@@ -319,7 +319,9 @@ void ResolverController::dump(DumpWriter& dw, unsigned netId) {
            dw.println("No DNS servers defined");
        } else {
            dw.println("DnsEvent subsampling map: " +
                       android::base::Join(resolv_cache_dump_subsampling_map(netId), ' '));
                       android::base::Join(resolv_cache_dump_subsampling_map(netId, false), ' '));
            dw.println("DnsEvent subsampling map for MDNS: " +
                       android::base::Join(resolv_cache_dump_subsampling_map(netId, true), ' '));
            dw.println(
                    "DNS servers: # IP (total, successes, errors, timeouts, internal errors, "
                    "RTT avg, last sample)");
+21 −13
Original line number Diff line number Diff line
@@ -909,17 +909,19 @@ namespace {
// Sampling rate varies by return code; events to log are chosen randomly, with a
// probability proportional to the sampling rate.
constexpr const char DEFAULT_SUBSAMPLING_MAP[] = "default:8 0:400 2:110 7:110";
constexpr const char DEFAULT_MDNS_SUBSAMPLING_MAP[] = "default:1";

std::unordered_map<int, uint32_t> resolv_get_dns_event_subsampling_map() {
std::unordered_map<int, uint32_t> resolv_get_dns_event_subsampling_map(bool isMdns) {
    using android::base::ParseInt;
    using android::base::ParseUint;
    using android::base::Split;
    using server_configurable_flags::GetServerConfigurableFlag;
    std::unordered_map<int, uint32_t> sampling_rate_map{};
    std::vector<std::string> subsampling_vector =
            Split(GetServerConfigurableFlag("netd_native", "dns_event_subsample_map",
                                            DEFAULT_SUBSAMPLING_MAP),
                  " ");
    const char* flag = isMdns ? "mdns_event_subsample_map" : "dns_event_subsample_map";
    const char* defaultMap = isMdns ? DEFAULT_MDNS_SUBSAMPLING_MAP : DEFAULT_SUBSAMPLING_MAP;
    const std::vector<std::string> subsampling_vector =
            Split(GetServerConfigurableFlag("netd_native", flag, defaultMap), " ");

    for (const auto& pair : subsampling_vector) {
        std::vector<std::string> rate_denom = Split(pair, ":");
        int return_code;
@@ -1005,7 +1007,8 @@ struct Cache {
struct NetConfig {
    explicit NetConfig(unsigned netId) : netid(netId) {
        cache = std::make_unique<Cache>();
        dns_event_subsampling_map = resolv_get_dns_event_subsampling_map();
        dns_event_subsampling_map = resolv_get_dns_event_subsampling_map(false);
        mdns_event_subsampling_map = resolv_get_dns_event_subsampling_map(true);
    }
    int nameserverCount() { return nameserverSockAddrs.size(); }
    int setOptions(const ResolverOptionsParcel& resolverOptions) {
@@ -1036,6 +1039,7 @@ struct NetConfig {
    int wait_for_pending_req_timeout_count = 0;
    // Map format: ReturnCode:rate_denom
    std::unordered_map<int, uint32_t> dns_event_subsampling_map;
    std::unordered_map<int, uint32_t> mdns_event_subsampling_map;
    DnsStats dnsStats;

    // Customized hostname/address table will be stored in customizedTable.
@@ -1793,17 +1797,20 @@ int android_net_res_stats_get_info_for_net(unsigned netid, int* nscount,
    return info->revision_id;
}

std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid) {
std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid, bool is_mdns) {
    std::lock_guard guard(cache_mutex);
    NetConfig* netconfig = find_netconfig_locked(netid);
    if (netconfig == nullptr) return {};
    std::vector<std::string> result;
    for (const auto& pair : netconfig->dns_event_subsampling_map) {
    const auto& subsampling_map = (!is_mdns) ? netconfig->dns_event_subsampling_map
                                             : netconfig->mdns_event_subsampling_map;
    result.reserve(subsampling_map.size());
    for (const auto& [return_code, rate_denom] : subsampling_map) {
        result.push_back(fmt::format("{}:{}",
                                     (pair.first == DNSEVENT_SUBSAMPLING_MAP_DEFAULT_KEY)
                                     (return_code == DNSEVENT_SUBSAMPLING_MAP_DEFAULT_KEY)
                                             ? "default"
                                             : std::to_string(pair.first),
                                     pair.second));
                                             : std::to_string(return_code),
                                     rate_denom));
    }
    return result;
}
@@ -1812,11 +1819,12 @@ std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid) {
// a sampling factor derived from the netid and the return code.
//
// Returns the subsampling rate if the event should be sampled, or 0 if it should be discarded.
uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code) {
uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code, bool is_mdns) {
    std::lock_guard guard(cache_mutex);
    NetConfig* netconfig = find_netconfig_locked(netid);
    if (netconfig == nullptr) return 0;  // Don't log anything at all.
    const auto& subsampling_map = netconfig->dns_event_subsampling_map;
    const auto& subsampling_map = (!is_mdns) ? netconfig->dns_event_subsampling_map
                                             : netconfig->mdns_event_subsampling_map;
    auto search_returnCode = subsampling_map.find(return_code);
    uint32_t denom;
    if (search_returnCode != subsampling_map.end()) {
+2 −2
Original line number Diff line number Diff line
@@ -50,8 +50,8 @@ void resolv_populate_res_for_net(ResState* statp);

std::vector<unsigned> resolv_list_caches();

std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid);
uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code);
std::vector<std::string> resolv_cache_dump_subsampling_map(unsigned netid, bool is_mdns);
uint32_t resolv_cache_get_subsampling_denom(unsigned netid, int return_code, bool is_mdns);

typedef enum {
    RESOLV_CACHE_UNSUPPORTED, /* the cache can't handle that kind of queries */
+72 −22
Original line number Diff line number Diff line
@@ -910,11 +910,12 @@ namespace {
constexpr int EAI_OK = 0;
constexpr char DNS_EVENT_SUBSAMPLING_MAP_FLAG[] =
        "persist.device_config.netd_native.dns_event_subsample_map";
constexpr char MDNS_EVENT_SUBSAMPLING_MAP_FLAG[] =
        "persist.device_config.netd_native.mdns_event_subsample_map";

class ScopedCacheCreate {
  public:
    explicit ScopedCacheCreate(unsigned netid, const char* subsampling_map,
                               const char* property = DNS_EVENT_SUBSAMPLING_MAP_FLAG)
    explicit ScopedCacheCreate(unsigned netid, const char* subsampling_map, const char* property)
        : mStoredNetId(netid), mStoredProperty(property) {
        property_get(property, mStoredMap, "");
        property_set(property, subsampling_map);
@@ -936,45 +937,94 @@ class ScopedCacheCreate {
TEST_F(ResolvCacheTest, DnsEventSubsampling) {
    // Test defaults, default flag is "default:8 0:400 2:110 7:110" if no experiment flag is set
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "");
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_AGAIN), 110U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 110U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 400U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS),
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "", DNS_EVENT_SUBSAMPLING_MAP_FLAG);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_AGAIN, false), 110U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, false), 110U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, false), 400U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS, false),
                  8U);  // default
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, false),
                    testing::UnorderedElementsAreArray({"default:8", "0:400", "2:110", "7:110"}));
    }
    // Now change the experiment flag to "0:42 default:666"
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:42 default:666");
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 42U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA),
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:42 default:666",
                                            DNS_EVENT_SUBSAMPLING_MAP_FLAG);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, false), 42U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, false),
                  666U);  // default
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, false),
                    testing::UnorderedElementsAreArray({"default:666", "0:42"}));
    }
    // Now change the experiment flag to something illegal
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "asvaxx");
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "asvaxx", DNS_EVENT_SUBSAMPLING_MAP_FLAG);
        // 0(disable log) is the default value if experiment flag is invalid.
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 0U);
        EXPECT_TRUE(resolv_cache_dump_subsampling_map(TEST_NETID).empty());
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, false), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, false), 0U);
        EXPECT_TRUE(resolv_cache_dump_subsampling_map(TEST_NETID, false).empty());
    }
    // Test negative and zero denom
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:-42 default:-666 7:10 10:0");
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:-42 default:-666 7:10 10:0",
                                            DNS_EVENT_SUBSAMPLING_MAP_FLAG);
        // 0(disable log) is the default value if no valid denom is set
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA), 10U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_SOCKTYPE), 0U);
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID),
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, false), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS, false), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, false), 10U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_SOCKTYPE, false), 0U);
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, false),
                    testing::UnorderedElementsAreArray({"7:10", "10:0"}));
    }
}

TEST_F(ResolvCacheTest, MdnsEventSubsampling) {
    // Test defaults, DEFAULT_MDNS_SUBSAMPLING_MAP is "default:1" if no experiment flag is set
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "", MDNS_EVENT_SUBSAMPLING_MAP_FLAG);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_AGAIN, true),
                  1U);  // default for all return_code
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, true), 1U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS, true), 1U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, true), 1U);
        // not equal to DEFAULT_SUBSAMPLING_MAP[] = "default:8 0:400 2:110 7:110";
        EXPECT_NE(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_AGAIN, true), 110U);
        EXPECT_NE(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, true), 110U);
        EXPECT_NE(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, true), 400U);
        EXPECT_NE(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS, true), 8U);
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, true),
                    testing::UnorderedElementsAreArray({"default:1"}));
    }
    // Now change the experiment flag to "default:1 0:10"
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:10 default:1",
                                            MDNS_EVENT_SUBSAMPLING_MAP_FLAG);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, true), 10U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, true), 1U);  // default
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, true),
                    testing::UnorderedElementsAreArray({"0:10", "default:1"}));
    }
    // Now change the experiment flag to something illegal
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "asvaxx", MDNS_EVENT_SUBSAMPLING_MAP_FLAG);
        // 0(disable log) is the default value if experiment flag is invalid.
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, true), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, true), 0U);
        EXPECT_TRUE(resolv_cache_dump_subsampling_map(TEST_NETID, true).empty());
    }
    // Test negative and zero denom
    {
        ScopedCacheCreate scopedCacheCreate(TEST_NETID, "0:-42 default:-666 7:10 10:0",
                                            MDNS_EVENT_SUBSAMPLING_MAP_FLAG);
        // 0(disable log) is the default value if no valid denom is set
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_OK, true), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_BADFLAGS, true), 0U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_NODATA, true), 10U);
        EXPECT_EQ(resolv_cache_get_subsampling_denom(TEST_NETID, EAI_SOCKTYPE, true), 0U);
        EXPECT_THAT(resolv_cache_dump_subsampling_map(TEST_NETID, true),
                    testing::UnorderedElementsAreArray({"7:10", "10:0"}));
    }
}
// TODO: Tests for NetConfig, including:
//     - res_stats
//         -- _resolv_cache_add_resolver_stats_sample()