Merge "Implement waiting for IPv4 address for an interface"

This commit is contained in:
Tomasz Wasilczyk
2022-07-22 02:45:29 +00:00
committed by Android (Google) Code Review
18 changed files with 423 additions and 136 deletions

View File

@@ -47,7 +47,7 @@ static SocketParams getSocketParams(int domain) {
return params;
}
bool send(unsigned long request, struct ifreq& ifr) {
int trySend(unsigned long request, struct ifreq& ifr) {
const auto sp = getSocketParams(socketDomain);
base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol));
if (!sock.ok()) {
@@ -55,7 +55,12 @@ bool send(unsigned long request, struct ifreq& ifr) {
return false;
}
if (ioctl(sock.get(), request, &ifr) < 0) {
if (ioctl(sock.get(), request, &ifr) < 0) return errno;
return 0;
}
bool send(unsigned long request, struct ifreq& ifr) {
if (trySend(request, ifr) != 0) {
PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
return false;
}

View File

@@ -27,6 +27,15 @@ namespace android::netdevice::ifreqs {
*/
extern std::atomic_int socketDomain;
/**
* Tries to send ioctl interface request.
*
* \param request Request type (such as SIOCGIFFLAGS)
* \param ifr Request data (both input and output)
* \return error code of the call (0 for success)
*/
int trySend(unsigned long request, struct ifreq& ifr);
/**
* Sends ioctl interface request.
*

View File

@@ -67,21 +67,33 @@ enum class WaitCondition {
*/
PRESENT_AND_UP,
/**
* Interface is up and with IPv4 address configured.
*/
PRESENT_AND_IPV4,
/**
* Interface is down or not present (disconnected) at all.
*/
DOWN_OR_GONE,
};
enum class Quantifier {
ALL_OF,
ANY_OF,
};
/**
* Listens for interface changes until anticipated condition takes place.
*
* \param ifnames List of interfaces to watch for.
* \param cnd Awaited condition.
* \param allOf true if all interfaces need to satisfy the condition, false if only one satistying
* \param quant Whether all interfaces need to satisfy the condition or just one satistying
* interface should stop the wait.
* \return name of one interface that satisfied the condition
*/
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
Quantifier quant = Quantifier::ALL_OF);
/**
* Brings network interface up.

View File

@@ -100,23 +100,36 @@ std::optional<bool> isUp(std::string ifname) {
return ifr.ifr_flags & IFF_UP;
}
static bool hasIpv4(std::string ifname) {
auto ifr = ifreqs::fromName(ifname);
switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) {
case 0:
return true;
case EADDRNOTAVAIL:
case ENODEV:
return false;
default:
PLOG(WARNING) << "Failed checking IPv4 address";
return false;
}
}
struct WaitState {
bool present;
bool up;
bool hasIpv4Addr;
bool satisfied(WaitCondition cnd) const {
switch (cnd) {
case WaitCondition::PRESENT:
if (present) return true;
break;
return present;
case WaitCondition::PRESENT_AND_UP:
if (present && up) return true;
break;
return present && up;
case WaitCondition::PRESENT_AND_IPV4:
return present && up && hasIpv4Addr;
case WaitCondition::DOWN_OR_GONE:
if (!present || !up) return true;
break;
return !present || !up;
}
return false;
}
};
@@ -126,11 +139,22 @@ static std::string toString(WaitCondition cnd) {
return "become present";
case WaitCondition::PRESENT_AND_UP:
return "come up";
case WaitCondition::PRESENT_AND_IPV4:
return "get IPv4 address";
case WaitCondition::DOWN_OR_GONE:
return "go down";
}
}
static std::string toString(Quantifier quant) {
switch (quant) {
case Quantifier::ALL_OF:
return "all of";
case Quantifier::ANY_OF:
return "any of";
}
}
static std::string toString(const std::set<std::string>& ifnames) {
std::stringstream ss;
std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
@@ -139,50 +163,73 @@ static std::string toString(const std::set<std::string>& ifnames) {
return str;
}
void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
Quantifier quant) {
nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
using StatesMap = std::map<std::string, WaitState>;
StatesMap states = {};
for (const auto ifname : ifnames) {
const auto present = exists(ifname);
const auto up = present && isUp(ifname).value_or(false);
states[ifname] = {present, up};
const auto hasIpv4Addr = present && hasIpv4(ifname);
states[ifname] = {present, up, hasIpv4Addr};
}
const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
return it.second.satisfied(cnd);
};
const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() {
if (allOf) {
return std::all_of(states.begin(), states.end(), mapConditionChecker);
} else {
return std::any_of(states.begin(), states.end(), mapConditionChecker);
const auto isFullySatisfied = [&states, quant,
mapConditionChecker]() -> std::optional<std::string> {
if (quant == Quantifier::ALL_OF) {
if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {};
return states.begin()->first;
} else { // Quantifier::ANY_OF
const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker);
if (it == states.end()) return {};
return it->first;
}
};
if (isFullySatisfied()) return;
if (const auto iface = isFullySatisfied()) return iface;
LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to "
LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to "
<< toString(cnd);
for (const auto rawMsg : sock) {
const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
if (!msg.has_value()) continue;
if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
msg.has_value()) {
// Interface added / removed
const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
if (ifnames.count(ifname) == 0) continue;
const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
if (ifnames.count(ifname) == 0) continue;
auto& state = states[ifname];
state.present = (msg->header.nlmsg_type != RTM_DELLINK);
state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0;
if (!state.present) state.hasIpv4Addr = false;
const bool present = (msg->header.nlmsg_type != RTM_DELLINK);
const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0;
states[ifname] = {present, up};
} else if (const auto msg =
nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR});
msg.has_value()) {
// Address added / removed
const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
if (ifnames.count(ifname) == 0) continue;
if (isFullySatisfied()) {
LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
if (msg->header.nlmsg_type == RTM_NEWADDR) {
states[ifname].hasIpv4Addr = true;
} else {
// instead of tracking which one got deleted, let's just ask
states[ifname].hasIpv4Addr = hasIpv4(ifname);
}
}
if (const auto iface = isFullySatisfied()) {
LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames)
<< " to " << toString(cnd);
return;
return iface;
}
}
LOG(FATAL) << "Can't read Netlink socket";
return {};
}
} // namespace android::netdevice

View File

@@ -37,8 +37,10 @@ cc_library_static {
"protocols/generic/Unknown.cpp",
"protocols/generic/families/Mac80211hwsim.cpp",
"protocols/generic/families/Nl80211.cpp",
"protocols/route/Addr.cpp",
"protocols/route/Link.cpp",
"protocols/route/Route.cpp",
"protocols/route/attributes.cpp",
"protocols/route/structs.cpp",
"protocols/MessageDefinition.cpp",
"protocols/NetlinkProtocol.cpp",

View File

@@ -34,7 +34,7 @@ const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const
MessageDescriptor::MessageDescriptor(const std::string& name,
const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize)
const AttributeMap& attrTypes, size_t contentsSize)
: mName(name),
mContentsSize(contentsSize),
mMessageDetails(messageDetails),

View File

@@ -163,7 +163,7 @@ class MessageDescriptor {
protected:
MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize);
const AttributeMap& attrTypes, size_t contentsSize);
private:
const std::string mName;
@@ -183,7 +183,7 @@ class MessageDefinition : public MessageDescriptor {
MessageDefinition( //
const std::string& name,
const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
const std::initializer_list<AttributeMap::value_type> attrTypes = {})
const AttributeMap& attrTypes = {})
: MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {

View File

@@ -33,12 +33,12 @@ static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
return map;
}
static auto all = toMap({
std::make_unique<generic::Generic>(),
std::make_unique<route::Route>(),
});
std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
static auto all = toMap({
std::make_unique<generic::Generic>(),
std::make_unique<route::Route>(),
});
if (all.count(protocol) == 0) return std::nullopt;
return *all.find(protocol)->second.get();
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Addr.h"
#include "../structs.h"
#include "attributes.h"
#include "structs.h"
namespace android::nl::protocols::route {
using DataType = AttributeDefinition::DataType;
// clang-format off
Addr::Addr() : MessageDefinition<ifaddrmsg>("addr", {
{RTM_NEWADDR, {"NEWADDR", MessageGenre::New}},
{RTM_DELADDR, {"DELADDR", MessageGenre::Delete}},
{RTM_GETADDR, {"GETADDR", MessageGenre::Get}},
}, gAttributes) {}
static const FlagsMap ifaFlagsMap {
{IFA_F_SECONDARY, "SECONDARY"},
{IFA_F_NODAD, "NODAD"},
{IFA_F_OPTIMISTIC, "OPTIMISTIC"},
{IFA_F_DADFAILED, "DADFAILED"},
{IFA_F_HOMEADDRESS, "HOMEADDRESS"},
{IFA_F_DEPRECATED, "DEPRECATED"},
{IFA_F_TENTATIVE, "TENTATIVE"},
{IFA_F_PERMANENT, "PERMANENT"},
{IFA_F_MANAGETEMPADDR, "MANAGETEMPADDR"},
{IFA_F_NOPREFIXROUTE, "NOPREFIXROUTE"},
{IFA_F_MCAUTOJOIN, "MCAUTOJOIN"},
{IFA_F_STABLE_PRIVACY, "STABLE_PRIVACY"},
};
// clang-format on
void Addr::toStream(std::stringstream& ss, const ifaddrmsg& data) const {
ss << "ifaddrmsg{"
<< "family=" << familyToString(data.ifa_family)
<< ", prefixlen=" << unsigned(data.ifa_prefixlen) << ", flags=";
flagsToStream(ss, ifaFlagsMap, data.ifa_flags);
ss << ", scope=" << unsigned(data.ifa_scope) << ", index=" << data.ifa_index << "}";
}
} // namespace android::nl::protocols::route

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../MessageDefinition.h"
#include <linux/rtnetlink.h>
namespace android::nl::protocols::route {
class Addr : public MessageDefinition<ifaddrmsg> {
public:
Addr();
void toStream(std::stringstream& ss, const ifaddrmsg& data) const override;
};
} // namespace android::nl::protocols::route

View File

@@ -16,10 +16,7 @@
#include "Link.h"
#include "../structs.h"
#include "structs.h"
#include <net/if.h>
#include "attributes.h"
namespace android::nl::protocols::route {
@@ -30,83 +27,8 @@ Link::Link() : MessageDefinition<ifinfomsg>("link", {
{RTM_NEWLINK, {"NEWLINK", MessageGenre::New}},
{RTM_DELLINK, {"DELLINK", MessageGenre::Delete}},
{RTM_GETLINK, {"GETLINK", MessageGenre::Get}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
{IFLA_IFNAME, {"IFNAME", DataType::String}},
{IFLA_MTU, {"MTU", DataType::Uint}},
{IFLA_LINK, {"LINK", DataType::Uint}},
{IFLA_QDISC, {"QDISC", DataType::String}},
{IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
{IFLA_COST, {"COST"}},
{IFLA_PRIORITY, {"PRIORITY"}},
{IFLA_MASTER, {"MASTER", DataType::Uint}},
{IFLA_WIRELESS, {"WIRELESS"}},
{IFLA_PROTINFO, {"PROTINFO"}},
{IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
{IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
{IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
{IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
{IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
{IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
{IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
{IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
{IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
{IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
{IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
}}},
{IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
{IFLA_IFALIAS, {"IFALIAS", DataType::String}},
{IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
{IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
{IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
{IFLA_VF_PORTS, {"VF_PORTS"}},
{IFLA_PORT_SELF, {"PORT_SELF"}},
{IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
{AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
{IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
}}},
{AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
{IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
{IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
{IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_MCAST, {"INET6_MCAST"}},
{IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
{IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
{IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
}}},
}}},
{IFLA_GROUP, {"GROUP", DataType::Uint}},
{IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
{IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
{IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
{IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
{IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
{IFLA_CARRIER, {"CARRIER", DataType::Uint}},
{IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
{IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
{IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
{IFLA_LINK_NETNSID, {"LINK_NETNSID"}}, // NLA_S32
{IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
{IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
{IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
{IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
{IFLA_PAD, {"PAD"}},
{IFLA_XDP, {"XDP"}},
{IFLA_EVENT, {"EVENT", DataType::Uint}},
{IFLA_NEW_NETNSID, {"NEW_NETNSID"}}, // NLA_S32
{IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}}, // NLA_S32
{IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
{IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
{IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}}, // NLA_S32
{IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
{IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
{IFLA_PROP_LIST, {"PROP_LIST"}},
{IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
{IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
}) {}
// clang-format off
}, gAttributes) {}
// clang-format on
void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
ss << "ifinfomsg{"

View File

@@ -16,10 +16,16 @@
#include "Route.h"
#include "Addr.h"
#include "Link.h"
namespace android::nl::protocols::route {
Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {std::make_shared<Link>()}) {}
// clang-format off
Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {
std::make_shared<Addr>(),
std::make_shared<Link>(),
}) {}
// clang-format on
} // namespace android::nl::protocols::route

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "attributes.h"
#include "../structs.h"
#include "structs.h"
#include <linux/rtnetlink.h>
#include <net/if.h>
namespace android::nl::protocols::route {
using DataType = AttributeDefinition::DataType;
using Flags = AttributeDefinition::Flags;
// clang-format off
AttributeMap gAttributes = {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
{IFLA_IFNAME, {"IFNAME", DataType::StringNul}},
{IFLA_MTU, {"MTU", DataType::Uint}},
{IFLA_LINK, {"LINK", DataType::Uint}},
{IFLA_QDISC, {"QDISC", DataType::Raw, AttributeMap{}, Flags::Verbose}}, // should be DataType::String, but looks like binary blob
{IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
{IFLA_COST, {"COST", DataType::Uint}},
{IFLA_PRIORITY, {"PRIORITY"}},
{IFLA_MASTER, {"MASTER", DataType::Uint}},
{IFLA_WIRELESS, {"WIRELESS"}},
{IFLA_PROTINFO, {"PROTINFO"}},
{IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
{IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
{IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
{IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
{IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
{IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
{IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
{IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
{IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
{IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
{IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
}}},
{IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
{IFLA_IFALIAS, {"IFALIAS", DataType::String}},
{IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
{IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
{IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
{IFLA_VF_PORTS, {"VF_PORTS"}},
{IFLA_PORT_SELF, {"PORT_SELF"}},
{IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
{AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
{IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
}}},
{AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
{IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
{IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
{IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_MCAST, {"INET6_MCAST"}},
{IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
{IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
{IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
{IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
}}},
}}},
{IFLA_GROUP, {"GROUP", DataType::Uint}},
{IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
{IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
{IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
{IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
{IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
{IFLA_CARRIER, {"CARRIER", DataType::Uint}},
{IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
{IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
{IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
{IFLA_LINK_NETNSID, {"LINK_NETNSID"}}, // NLA_S32
{IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
{IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
{IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
{IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
{IFLA_PAD, {"PAD"}},
{IFLA_XDP, {"XDP"}},
{IFLA_EVENT, {"EVENT", DataType::Uint}},
{IFLA_NEW_NETNSID, {"NEW_NETNSID"}}, // NLA_S32
{IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}}, // NLA_S32
{IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
{IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
{IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}}, // NLA_S32
{IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
{IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
{IFLA_PROP_LIST, {"PROP_LIST"}},
{IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
{IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
};
// clang-format on
} // namespace android::nl::protocols::route

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../MessageDefinition.h"
namespace android::nl::protocols::route {
extern AttributeMap gAttributes;
} // namespace android::nl::protocols::route

View File

@@ -46,4 +46,58 @@ void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
<< data.retrans_time << '}';
}
// clang-format off
std::string familyToString(sa_family_t family) {
switch (family) {
case AF_UNSPEC: return "UNSPEC";
case AF_UNIX: return "UNIX";
case AF_INET: return "INET";
case AF_AX25: return "AX25";
case AF_IPX: return "IPX";
case AF_APPLETALK: return "APPLETALK";
case AF_NETROM: return "NETROM";
case AF_BRIDGE: return "BRIDGE";
case AF_ATMPVC: return "ATMPVC";
case AF_X25: return "X25";
case AF_INET6: return "INET6";
case AF_ROSE: return "ROSE";
case AF_DECnet: return "DECnet";
case AF_NETBEUI: return "NETBEUI";
case AF_SECURITY: return "SECURITY";
case AF_KEY: return "KEY";
case AF_NETLINK: return "NETLINK";
case AF_PACKET: return "PACKET";
case AF_ASH: return "ASH";
case AF_ECONET: return "ECONET";
case AF_ATMSVC: return "ATMSVC";
case AF_RDS: return "RDS";
case AF_SNA: return "SNA";
case AF_IRDA: return "IRDA";
case AF_PPPOX: return "PPPOX";
case AF_WANPIPE: return "WANPIPE";
case AF_LLC: return "LLC";
case 27 /*AF_IB*/: return "IB";
case 28 /*AF_MPLS*/: return "MPLS";
case AF_CAN: return "CAN";
case AF_TIPC: return "TIPC";
case AF_BLUETOOTH: return "BLUETOOTH";
case AF_IUCV: return "IUCV";
case AF_RXRPC: return "RXRPC";
case AF_ISDN: return "ISDN";
case AF_PHONET: return "PHONET";
case AF_IEEE802154: return "IEEE802154";
case AF_CAIF: return "CAIF";
case AF_ALG: return "ALG";
case AF_NFC: return "NFC";
case AF_VSOCK: return "VSOCK";
case AF_KCM: return "KCM";
case AF_QIPCRTR: return "QIPCRTR";
case 43 /*AF_SMC*/: return "SMC";
case 44 /*AF_XDP*/: return "XDP";
default:
return std::to_string(family);
}
}
// clang-format on
} // namespace android::nl::protocols::route

View File

@@ -19,6 +19,7 @@
#include <libnl++/Buffer.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <sstream>
@@ -30,6 +31,8 @@ void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
// ifla_cacheinfo
void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
std::string familyToString(sa_family_t family);
// rtnl_link_stats or rtnl_link_stats64
template <typename T>
void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {

View File

@@ -22,24 +22,27 @@ namespace android::nl::protocols {
AttributeDefinition::ToStream flagsToStream(FlagsMap flags) {
return [flags](std::stringstream& ss, const Buffer<nlattr> attr) {
auto val = attr.data<uint64_t>().copyFirst();
auto value = attr.data<uint64_t>().copyFirst();
flagsToStream(ss, flags, value);
};
}
bool first = true;
for (const auto& [flag, name] : flags) {
if ((val & flag) != flag) continue;
val &= ~flag;
if (!first) ss << '|';
first = false;
ss << name;
}
if (val == 0) return;
void flagsToStream(std::stringstream& ss, const FlagsMap& flags, uint64_t val) {
bool first = true;
for (const auto& [flag, name] : flags) {
if ((val & flag) != flag) continue;
val &= ~flag;
if (!first) ss << '|';
ss << std::hex << val << std::dec;
};
first = false;
ss << name;
}
if (val == 0) return;
if (!first) ss << '|';
ss << std::hex << val << std::dec;
}
void hwaddrToStream(std::stringstream& ss, const Buffer<nlattr> attr) {

View File

@@ -34,6 +34,7 @@ void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
typedef std::map<uint64_t, std::string> FlagsMap;
AttributeDefinition::ToStream flagsToStream(FlagsMap flags);
void flagsToStream(std::stringstream& ss, const FlagsMap& flags, uint64_t value);
void hwaddrToStream(std::stringstream& ss, const Buffer<nlattr> attr);