blob: 65d3859465f3c406f9f29c86c36f2db41c08cfe6 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_NET_RTNL_MESSAGE_H_
#define SHILL_NET_RTNL_MESSAGE_H_
#include <string>
#include <unordered_map>
#include <vector>
#include <base/macros.h>
#include <base/optional.h>
#include <base/stl_util.h>
#include "shill/net/byte_string.h"
#include "shill/net/ip_address.h"
#include "shill/net/shill_export.h"
struct rtattr;
namespace shill {
struct RTNLHeader;
using RTNLAttrMap = std::unordered_map<uint16_t, ByteString>;
// Helper class for processing rtnetlink messages. See uapi/linux/rtnetlink.h
// and rtnetlink manual page for details about the message binary encoding and
// meaning of struct fields populated by the kernel.
class SHILL_EXPORT RTNLMessage {
public:
enum Type {
kTypeUnknown,
kTypeLink,
kTypeAddress,
kTypeRoute,
kTypeRule,
kTypeRdnss,
kTypeDnssl,
kTypeNeighbor,
};
enum Mode { kModeUnknown, kModeGet, kModeAdd, kModeDelete, kModeQuery };
// Helper struct corresponding to struct ifinfomsg.
struct LinkStatus {
LinkStatus() : type(0), flags(0), change(0) {}
LinkStatus(unsigned int in_type,
unsigned int in_flags,
unsigned int in_change,
base::Optional<std::string> kind = base::nullopt)
: type(in_type), flags(in_flags), change(in_change), kind(kind) {}
// Device type. Corresponds to ifi_type.
unsigned int type;
// Device flags. Corresponds to ifi_flags.
unsigned int flags;
// Change mask. Corresponds to ifi_mask.
unsigned int change;
// Device kind, as defined by the device driver. Corresponds to rtattr
// IFLA_INFO_KIND nested inside rtattr IFLA_LINKINFO.
base::Optional<std::string> kind;
};
// Helper struct corresponding to struct ifaddrmsg.
struct AddressStatus {
AddressStatus() : prefix_len(0), flags(0), scope(0) {}
AddressStatus(unsigned char prefix_len_in,
unsigned char flags_in,
unsigned char scope_in)
: prefix_len(prefix_len_in), flags(flags_in), scope(scope_in) {}
// Prefix length of the address. Corresponds to ifa_prefixlen.
unsigned char prefix_len;
// Address flags. Corresponds to ifa_flags.
unsigned char flags;
// Address scope. Corresponds to ifa_scope.
unsigned char scope;
};
// Helper struct corresponding to struct rtmsg.
struct RouteStatus {
RouteStatus()
: dst_prefix(0),
src_prefix(0),
table(0),
protocol(0),
scope(0),
type(0),
flags(0) {}
RouteStatus(unsigned char dst_prefix_in,
unsigned char src_prefix_in,
unsigned char table_in,
unsigned char protocol_in,
unsigned char scope_in,
unsigned char type_in,
unsigned flags_in)
: dst_prefix(dst_prefix_in),
src_prefix(src_prefix_in),
table(table_in),
protocol(protocol_in),
scope(scope_in),
type(type_in),
flags(flags_in) {}
// Prefix length of the destination. Corresponds to rtm_dst_len.
unsigned char dst_prefix;
// Prefix length of the source. Corresponds to rtm_src_len.
unsigned char src_prefix;
// Legacy routing table id. Corresponds to rtm_table.
// TODO(b/154500323) This cannot expose correctly the per-device routing
// tables which starts with a +1000 offset. Instead this class should
// expose the RTA_TABLE rtattr for kTypeRoute messages and the FRA_TABLE
// rtattr for kTypeRule messages.
unsigned char table;
// Routing protocol. Corresponds to rtm_protocol.
unsigned char protocol;
// Distance to the destination. Corresponds to rtm_scope.
unsigned char scope;
// The type of route. Corresponds to rtm_type.
unsigned char type;
// Route flags. Corresponds to rtm_flags.
unsigned flags;
};
// Helper struct corresponding to struct ndmsg.
struct NeighborStatus {
NeighborStatus() : state(0), flags(0), type(0) {}
NeighborStatus(uint16_t state_in, uint8_t flags_in, uint8_t type_in)
: state(state_in), flags(flags_in), type(type_in) {}
std::string ToString() const;
// Neighbor state. Corresponds to ndm_state.
uint16_t state;
// Neighbor flags. Corresponds to ndm_flags.
uint8_t flags;
// Neighbor type. Corresponds to ndm_type.
uint8_t type;
};
struct RdnssOption {
RdnssOption() : lifetime(0) {}
RdnssOption(uint32_t lifetime_in, std::vector<IPAddress> addresses_in)
: lifetime(lifetime_in), addresses(addresses_in) {}
std::string ToString() const;
uint32_t lifetime;
std::vector<IPAddress> addresses;
};
// Empty constructor
RTNLMessage();
// Build an RTNL message from arguments
RTNLMessage(Type type,
Mode mode,
uint16_t flags,
uint32_t seq,
uint32_t pid,
int32_t interface_index,
IPAddress::Family family);
RTNLMessage(const RTNLMessage&) = delete;
RTNLMessage& operator=(const RTNLMessage&) = delete;
// Parse an RTNL message. Returns true on success.
bool Decode(const ByteString& data);
// Encode an RTNL message. Returns empty ByteString on failure.
ByteString Encode() const;
// Reset all fields.
void Reset();
// Getters and setters
Type type() const { return type_; }
Mode mode() const { return mode_; }
uint16_t flags() const { return flags_; }
uint32_t seq() const { return seq_; }
void set_seq(uint32_t seq) { seq_ = seq; }
uint32_t pid() const { return pid_; }
int32_t interface_index() const { return interface_index_; }
IPAddress::Family family() const { return family_; }
static std::string ModeToString(Mode mode);
static std::string TypeToString(Type type);
std::string ToString() const;
const LinkStatus& link_status() const { return link_status_; }
void set_link_status(const LinkStatus& link_status) {
link_status_ = link_status;
}
const AddressStatus& address_status() const { return address_status_; }
void set_address_status(const AddressStatus& address_status) {
address_status_ = address_status;
}
const RouteStatus& route_status() const { return route_status_; }
void set_route_status(const RouteStatus& route_status) {
route_status_ = route_status;
}
const RdnssOption& rdnss_option() const { return rdnss_option_; }
void set_rdnss_option(const RdnssOption& rdnss_option) {
rdnss_option_ = rdnss_option;
}
const NeighborStatus& neighbor_status() const { return neighbor_status_; }
void set_neighbor_status(const NeighborStatus& neighbor_status) {
neighbor_status_ = neighbor_status;
}
// GLint hates "unsigned short", and I don't blame it, but that's the
// type that's used in the system headers. Use uint16_t instead and hope
// that the conversion never ends up truncating on some strange platform.
bool HasAttribute(uint16_t attr) const {
return base::Contains(attributes_, attr);
}
const ByteString GetAttribute(uint16_t attr) const {
return HasAttribute(attr) ? attributes_.find(attr)->second : ByteString(0);
}
void SetAttribute(uint16_t attr, const ByteString& val) {
attributes_[attr] = val;
}
// Return the value of an rtattr attribute of type uint32_t.
uint32_t GetUint32Attribute(uint16_t attr) const;
// Returns the value of an rtattr attribute of type string. String attributes
// serialized by the kernel with nla_put_string() are null terminated and the
// null terminator is included in the underlying ByteString value. In case
// the ByteString does not contain any terminator, all the bytes of contained
// in the ByteString are copied into the standard string.
std::string GetStringAttribute(uint16_t attr) const;
// returns the IFLA_IFNAME attribute as standard string. This should only be
// used for RTNLMessages of type kTypeLink.
std::string GetIflaIfname() const;
// Returns the IFA_ADDRESS attribute as a shill::IPAddress. This should only
// be used for RTNLMessages of type kTypeAddress.
IPAddress GetIfaAddress() const;
// Returns the routing table id of RTNLMessages with type kTypeRoute.
uint32_t GetRtaTable() const;
// Returns the RTA_DST attribute as a shill::IPAddress for RTNLMessages of
// type kTypeRoute.
IPAddress GetRtaDst() const;
// Returns the RTA_SRC attribute as a shill::IPAddress for RTNLMessages of
// type kTypeRoute.
IPAddress GetRtaSrc() const;
// Returns the RTA_GATEWAY attribute as a shill::IPAddress for RTNLMessages of
// type kTypeRoute.
IPAddress GetRtaGateway() const;
// Returns the RTA_OIF output interface attribute as an interface index
// name for RTNLMessages of type kTypeRoute.
uint32_t GetRtaOif() const;
// Returns the RTA_OIF output interface attribute translated as an interface
// name for RTNLMessages of type kTypeRoute.
std::string GetRtaOifname() const;
// Returns the RTA_PRIORITY attribute for RTNLMessages of type kTypeRoute.
uint32_t GetRtaPriority() const;
// Returns the lookup routing table id of RTNLMessages with type kTypeRule.
uint32_t GetFraTable() const;
// Returns the input interface name of RTNLMessages with type kTypeRule.
std::string GetFraOifname() const;
// Returns the output interface name of RTNLMessages with type kTypeRule.
std::string GetFraIifname() const;
// Returns the fwmark value of RTNLMessages with type kTypeRule.
uint32_t GetFraFwmark() const;
// Returns the fwmask value of RTNLMessages with type kTypeRule.
uint32_t GetFraFwmask() const;
// Returns the FRA_PRIORITY attribute for RTNLMessages of type kTypeRule.
uint32_t GetFraPriority() const;
// Returns the FRA_SRC attribute as a shill::IPAddress for RTNLMessages of
// type kTypeRule.
IPAddress GetFraSrc() const;
// Returns the FRA_DST attribute as a shill::IPAddress for RTNLMessages of
// type kTypeRule.
IPAddress GetFraDst() const;
private:
SHILL_PRIVATE bool DecodeInternal(const ByteString& msg);
SHILL_PRIVATE bool DecodeLink(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool DecodeAddress(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool DecodeRoute(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool DecodeRule(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool DecodeNdUserOption(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool ParseRdnssOption(const uint8_t* data,
int length,
uint32_t lifetime);
SHILL_PRIVATE bool DecodeNeighbor(const RTNLHeader* hdr,
rtattr** attr_data,
int* attr_length);
SHILL_PRIVATE bool EncodeLink(RTNLHeader* hdr) const;
SHILL_PRIVATE bool EncodeAddress(RTNLHeader* hdr) const;
SHILL_PRIVATE bool EncodeRoute(RTNLHeader* hdr) const;
SHILL_PRIVATE bool EncodeNeighbor(RTNLHeader* hdr) const;
// Type and mode of the message, corresponding to a subset of the RTM_* enum
// defined in uapi/linux/rtnetlink.h
Type type_;
Mode mode_;
// Netlink request flags. Corresponds to nlmsg_flags in struct nlmsghdr.
uint16_t flags_;
// Arbitrary msg id used for response correlation. Corresponds to nlmsg_seq in
// struct nlmsghdr.
uint32_t seq_;
// The sender id. Corresponds to nlmsg_pid in struct nlmsghdr.
uint32_t pid_;
// Corresponds to ifi_index (kTypeLink), ifa_index (kTypeAddress), ndm_ifindex
// (kTypeNeighbor).
int32_t interface_index_;
// Corresponds to ifi_family (kTypeLink), ifa_family (kTypeAddress),
// rtm_family (kTypeRoute and kTypeRule), ndm_family (kTypeNeighbor). Always
// IPv6 for neighbor discovery options (kTypeRdnss, kTypeDnssl).
IPAddress::Family family_;
// Details specific to a message type.
LinkStatus link_status_;
AddressStatus address_status_;
RouteStatus route_status_;
NeighborStatus neighbor_status_;
RdnssOption rdnss_option_;
// Additional rtattr contained in the message.
RTNLAttrMap attributes_;
// NOTE: Update Reset() accordingly when adding a new member field.
};
} // namespace shill
#endif // SHILL_NET_RTNL_MESSAGE_H_