diff options
Diffstat (limited to '')
-rw-r--r-- | src/msg/msg_types.h | 851 |
1 files changed, 851 insertions, 0 deletions
diff --git a/src/msg/msg_types.h b/src/msg/msg_types.h new file mode 100644 index 000000000..f1f0c5e5c --- /dev/null +++ b/src/msg/msg_types.h @@ -0,0 +1,851 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_MSG_TYPES_H +#define CEPH_MSG_TYPES_H + +#include <sstream> + +#include <netinet/in.h> + +#include "include/ceph_features.h" +#include "include/types.h" +#include "include/blobhash.h" +#include "include/encoding.h" + +#define MAX_PORT_NUMBER 65535 + +#ifdef _WIN32 +// ceph_sockaddr_storage matches the Linux format. +#define AF_INET6_LINUX 10 +#endif + +namespace ceph { + class Formatter; +} + +std::ostream& operator<<(std::ostream& out, const sockaddr_storage &ss); +std::ostream& operator<<(std::ostream& out, const sockaddr *sa); + +typedef uint8_t entity_type_t; + +class entity_name_t { +public: + entity_type_t _type; + int64_t _num; + +public: + static const int TYPE_MON = CEPH_ENTITY_TYPE_MON; + static const int TYPE_MDS = CEPH_ENTITY_TYPE_MDS; + static const int TYPE_OSD = CEPH_ENTITY_TYPE_OSD; + static const int TYPE_CLIENT = CEPH_ENTITY_TYPE_CLIENT; + static const int TYPE_MGR = CEPH_ENTITY_TYPE_MGR; + + static const int64_t NEW = -1; + + // cons + entity_name_t() : _type(0), _num(0) { } + entity_name_t(int t, int64_t n) : _type(t), _num(n) { } + explicit entity_name_t(const ceph_entity_name &n) : + _type(n.type), _num(n.num) { } + + // static cons + static entity_name_t MON(int64_t i=NEW) { return entity_name_t(TYPE_MON, i); } + static entity_name_t MDS(int64_t i=NEW) { return entity_name_t(TYPE_MDS, i); } + static entity_name_t OSD(int64_t i=NEW) { return entity_name_t(TYPE_OSD, i); } + static entity_name_t CLIENT(int64_t i=NEW) { return entity_name_t(TYPE_CLIENT, i); } + static entity_name_t MGR(int64_t i=NEW) { return entity_name_t(TYPE_MGR, i); } + + int64_t num() const { return _num; } + int type() const { return _type; } + const char *type_str() const { + return ceph_entity_type_name(type()); + } + + bool is_new() const { return num() < 0; } + + bool is_client() const { return type() == TYPE_CLIENT; } + bool is_mds() const { return type() == TYPE_MDS; } + bool is_osd() const { return type() == TYPE_OSD; } + bool is_mon() const { return type() == TYPE_MON; } + bool is_mgr() const { return type() == TYPE_MGR; } + + operator ceph_entity_name() const { + ceph_entity_name n = { _type, init_le64(_num) }; + return n; + } + + bool parse(const std::string& s) { + const char *start = s.c_str(); + char *end; + bool got = parse(start, &end); + return got && end == start + s.length(); + } + bool parse(const char *start, char **end) { + if (strstr(start, "mon.") == start) { + _type = TYPE_MON; + start += 4; + } else if (strstr(start, "osd.") == start) { + _type = TYPE_OSD; + start += 4; + } else if (strstr(start, "mds.") == start) { + _type = TYPE_MDS; + start += 4; + } else if (strstr(start, "client.") == start) { + _type = TYPE_CLIENT; + start += 7; + } else if (strstr(start, "mgr.") == start) { + _type = TYPE_MGR; + start += 4; + } else { + return false; + } + if (isspace(*start)) + return false; + _num = strtoll(start, end, 10); + if (*end == NULL || *end == start) + return false; + return true; + } + + DENC(entity_name_t, v, p) { + denc(v._type, p); + denc(v._num, p); + } + void dump(ceph::Formatter *f) const; + + static void generate_test_instances(std::list<entity_name_t*>& o); +}; +WRITE_CLASS_DENC(entity_name_t) + +inline bool operator== (const entity_name_t& l, const entity_name_t& r) { + return (l.type() == r.type()) && (l.num() == r.num()); } +inline bool operator!= (const entity_name_t& l, const entity_name_t& r) { + return (l.type() != r.type()) || (l.num() != r.num()); } +inline bool operator< (const entity_name_t& l, const entity_name_t& r) { + return (l.type() < r.type()) || (l.type() == r.type() && l.num() < r.num()); } + +inline std::ostream& operator<<(std::ostream& out, const entity_name_t& addr) { + //if (addr.is_namer()) return out << "namer"; + if (addr.is_new() || addr.num() < 0) + return out << addr.type_str() << ".?"; + else + return out << addr.type_str() << '.' << addr.num(); +} +inline std::ostream& operator<<(std::ostream& out, const ceph_entity_name& addr) { + return out << entity_name_t{addr.type, static_cast<int64_t>(addr.num)}; +} + +namespace std { + template<> struct hash< entity_name_t > + { + size_t operator()( const entity_name_t &m ) const + { + return rjhash32(m.type() ^ m.num()); + } + }; +} // namespace std + +// define a wire format for sockaddr that matches Linux's. +struct ceph_sockaddr_storage { + ceph_le16 ss_family; + __u8 __ss_padding[128 - sizeof(ceph_le16)]; + + void encode(ceph::buffer::list& bl) const { + struct ceph_sockaddr_storage ss = *this; + ss.ss_family = htons(ss.ss_family); + ceph::encode_raw(ss, bl); + } + + void decode(ceph::buffer::list::const_iterator& bl) { + struct ceph_sockaddr_storage ss; + ceph::decode_raw(ss, bl); + ss.ss_family = ntohs(ss.ss_family); + *this = ss; + } +} __attribute__ ((__packed__)); +WRITE_CLASS_ENCODER(ceph_sockaddr_storage) + +/* + * encode sockaddr.ss_family as network byte order + */ +static inline void encode(const sockaddr_storage& a, ceph::buffer::list& bl) { +#if defined(__linux__) + struct sockaddr_storage ss = a; + ss.ss_family = htons(ss.ss_family); + ceph::encode_raw(ss, bl); +#elif defined(__FreeBSD__) || defined(__APPLE__) + ceph_sockaddr_storage ss{}; + auto src = (unsigned char const *)&a; + auto dst = (unsigned char *)&ss; + src += sizeof(a.ss_len); + ss.ss_family = a.ss_family; + src += sizeof(a.ss_family); + dst += sizeof(ss.ss_family); + const auto copy_size = std::min((unsigned char*)(&a + 1) - src, + (unsigned char*)(&ss + 1) - dst); + ::memcpy(dst, src, copy_size); + encode(ss, bl); +#elif defined(_WIN32) + ceph_sockaddr_storage ss{}; + ::memcpy(&ss, &a, std::min(sizeof(ss), sizeof(a))); + // The Windows AF_INET6 definition doesn't match the Linux one. + if (a.ss_family == AF_INET6) { + ss.ss_family = AF_INET6_LINUX; + } + encode(ss, bl); +#else + ceph_sockaddr_storage ss; + ::memset(&ss, '\0', sizeof(ss)); + ::memcpy(&ss, &a, std::min(sizeof(ss), sizeof(a))); + encode(ss, bl); +#endif +} +static inline void decode(sockaddr_storage& a, + ceph::buffer::list::const_iterator& bl) { +#if defined(__linux__) + ceph::decode_raw(a, bl); + a.ss_family = ntohs(a.ss_family); +#elif defined(__FreeBSD__) || defined(__APPLE__) + ceph_sockaddr_storage ss{}; + decode(ss, bl); + auto src = (unsigned char const *)&ss; + auto dst = (unsigned char *)&a; + a.ss_len = 0; + dst += sizeof(a.ss_len); + a.ss_family = ss.ss_family; + src += sizeof(ss.ss_family); + dst += sizeof(a.ss_family); + auto const copy_size = std::min((unsigned char*)(&ss + 1) - src, + (unsigned char*)(&a + 1) - dst); + ::memcpy(dst, src, copy_size); +#elif defined(_WIN32) + ceph_sockaddr_storage ss{}; + decode(ss, bl); + ::memcpy(&a, &ss, std::min(sizeof(ss), sizeof(a))); + if (a.ss_family == AF_INET6_LINUX) { + a.ss_family = AF_INET6; + } +#else + ceph_sockaddr_storage ss{}; + decode(ss, bl); + ::memcpy(&a, &ss, std::min(sizeof(ss), sizeof(a))); +#endif +} + +/* + * an entity's network address. + * includes a random value that prevents it from being reused. + * thus identifies a particular process instance. + * + * This also happens to work to support cidr ranges, in which + * case the nonce contains the netmask. It's great! + */ +struct entity_addr_t { + typedef enum { + TYPE_NONE = 0, + TYPE_LEGACY = 1, ///< legacy msgr1 protocol (ceph jewel and older) + TYPE_MSGR2 = 2, ///< msgr2 protocol (new in ceph kraken) + TYPE_ANY = 3, ///< ambiguous + TYPE_CIDR = 4, + } type_t; + static const type_t TYPE_DEFAULT = TYPE_MSGR2; + static std::string_view get_type_name(int t) { + switch (t) { + case TYPE_NONE: return "none"; + case TYPE_LEGACY: return "v1"; + case TYPE_MSGR2: return "v2"; + case TYPE_ANY: return "any"; + case TYPE_CIDR: return "cidr"; + default: return "???"; + } + }; + + __u32 type; + __u32 nonce; + union { + sockaddr sa; + sockaddr_in sin; + sockaddr_in6 sin6; + } u; + + entity_addr_t() : type(0), nonce(0) { + memset(&u, 0, sizeof(u)); + } + entity_addr_t(__u32 _type, __u32 _nonce) : type(_type), nonce(_nonce) { + memset(&u, 0, sizeof(u)); + } + explicit entity_addr_t(const ceph_entity_addr &o) { + type = o.type; + nonce = o.nonce; + memcpy(&u, &o.in_addr, sizeof(u)); +#if !defined(__FreeBSD__) + u.sa.sa_family = ntohs(u.sa.sa_family); +#endif + } + + uint32_t get_type() const { return type; } + void set_type(uint32_t t) { type = t; } + bool is_legacy() const { return type == TYPE_LEGACY; } + bool is_msgr2() const { return type == TYPE_MSGR2; } + bool is_any() const { return type == TYPE_ANY; } + // this isn't a guarantee; some client addrs will match it + bool maybe_cidr() const { return get_port() == 0 && nonce != 0; } + + __u32 get_nonce() const { return nonce; } + void set_nonce(__u32 n) { nonce = n; } + + int get_family() const { + return u.sa.sa_family; + } + void set_family(int f) { + u.sa.sa_family = f; + } + + bool is_ipv4() const { + return u.sa.sa_family == AF_INET; + } + bool is_ipv6() const { + return u.sa.sa_family == AF_INET6; + } + + sockaddr_in &in4_addr() { + return u.sin; + } + const sockaddr_in &in4_addr() const{ + return u.sin; + } + sockaddr_in6 &in6_addr(){ + return u.sin6; + } + const sockaddr_in6 &in6_addr() const{ + return u.sin6; + } + const sockaddr *get_sockaddr() const { + return &u.sa; + } + size_t get_sockaddr_len() const { + switch (u.sa.sa_family) { + case AF_INET: + return sizeof(u.sin); + case AF_INET6: + return sizeof(u.sin6); + } + return sizeof(u); + } + bool set_sockaddr(const struct sockaddr *sa) + { + switch (sa->sa_family) { + case AF_INET: + // pre-zero, since we're only copying a portion of the source + memset(&u, 0, sizeof(u)); + memcpy(&u.sin, sa, sizeof(u.sin)); + break; + case AF_INET6: + // pre-zero, since we're only copying a portion of the source + memset(&u, 0, sizeof(u)); + memcpy(&u.sin6, sa, sizeof(u.sin6)); + break; + case AF_UNSPEC: + memset(&u, 0, sizeof(u)); + break; + default: + return false; + } + return true; + } + + sockaddr_storage get_sockaddr_storage() const { + sockaddr_storage ss; + memcpy(&ss, &u, sizeof(u)); + memset((char*)&ss + sizeof(u), 0, sizeof(ss) - sizeof(u)); + return ss; + } + + void set_in4_quad(int pos, int val) { + u.sin.sin_family = AF_INET; + unsigned char *ipq = (unsigned char*)&u.sin.sin_addr.s_addr; + ipq[pos] = val; + } + void set_port(int port) { + switch (u.sa.sa_family) { + case AF_INET: + u.sin.sin_port = htons(port); + break; + case AF_INET6: + u.sin6.sin6_port = htons(port); + break; + default: + ceph_abort(); + } + } + int get_port() const { + switch (u.sa.sa_family) { + case AF_INET: + return ntohs(u.sin.sin_port); + case AF_INET6: + return ntohs(u.sin6.sin6_port); + } + return 0; + } + + operator ceph_entity_addr() const { + ceph_entity_addr a; + a.type = 0; + a.nonce = nonce; + a.in_addr = get_sockaddr_storage(); +#if !defined(__FreeBSD__) + a.in_addr.ss_family = htons(a.in_addr.ss_family); +#endif + return a; + } + + bool probably_equals(const entity_addr_t &o) const { + if (get_port() != o.get_port()) + return false; + if (get_nonce() != o.get_nonce()) + return false; + if (is_blank_ip() || o.is_blank_ip()) + return true; + if (memcmp(&u, &o.u, sizeof(u)) == 0) + return true; + return false; + } + + bool is_same_host(const entity_addr_t &o) const { + if (u.sa.sa_family != o.u.sa.sa_family) + return false; + if (u.sa.sa_family == AF_INET) + return u.sin.sin_addr.s_addr == o.u.sin.sin_addr.s_addr; + if (u.sa.sa_family == AF_INET6) + return memcmp(u.sin6.sin6_addr.s6_addr, + o.u.sin6.sin6_addr.s6_addr, + sizeof(u.sin6.sin6_addr.s6_addr)) == 0; + return false; + } + + bool is_blank_ip() const { + switch (u.sa.sa_family) { + case AF_INET: + return u.sin.sin_addr.s_addr == INADDR_ANY; + case AF_INET6: + return memcmp(&u.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0; + default: + return true; + } + } + + bool is_ip() const { + switch (u.sa.sa_family) { + case AF_INET: + case AF_INET6: + return true; + default: + return false; + } + } + + std::string ip_only_to_str() const; + std::string ip_n_port_to_str() const; + + std::string get_legacy_str() const { + std::ostringstream ss; + ss << get_sockaddr() << "/" << get_nonce(); + return ss.str(); + } + + bool parse(const std::string_view s); + bool parse(const char *s, const char **end = 0, int type=0); + + void decode_legacy_addr_after_marker(ceph::buffer::list::const_iterator& bl) + { + using ceph::decode; + __u8 marker; + __u16 rest; + decode(marker, bl); + decode(rest, bl); + decode(nonce, bl); + sockaddr_storage ss; + decode(ss, bl); + set_sockaddr((sockaddr*)&ss); + if (get_family() == AF_UNSPEC) { + type = TYPE_NONE; + } else { + type = TYPE_LEGACY; + } + } + + // Right now, these only deal with sockaddr_storage that have only family and content. + // Apparently on BSD there is also an ss_len that we need to handle; this requires + // broader study + + void encode(ceph::buffer::list& bl, uint64_t features) const { + using ceph::encode; + if ((features & CEPH_FEATURE_MSG_ADDR2) == 0) { + encode((__u32)0, bl); + encode(nonce, bl); + sockaddr_storage ss = get_sockaddr_storage(); + encode(ss, bl); + return; + } + encode((__u8)1, bl); + ENCODE_START(1, 1, bl); + if (HAVE_FEATURE(features, SERVER_NAUTILUS)) { + encode(type, bl); + } else { + // map any -> legacy for old clients. this is primary for the benefit + // of OSDMap's blocklist, but is reasonable in general since any: is + // meaningless for pre-nautilus clients or daemons. + auto t = type; + if (t == TYPE_ANY) { + t = TYPE_LEGACY; + } + encode(t, bl); + } + encode(nonce, bl); + __u32 elen = get_sockaddr_len(); +#if (__FreeBSD__) || defined(__APPLE__) + elen -= sizeof(u.sa.sa_len); +#endif + encode(elen, bl); + if (elen) { + uint16_t ss_family = u.sa.sa_family; +#if defined(_WIN32) + if (ss_family == AF_INET6) { + ss_family = AF_INET6_LINUX; + } +#endif + encode(ss_family, bl); + elen -= sizeof(u.sa.sa_family); + bl.append(u.sa.sa_data, elen); + } + ENCODE_FINISH(bl); + } + void decode(ceph::buffer::list::const_iterator& bl) { + using ceph::decode; + __u8 marker; + decode(marker, bl); + if (marker == 0) { + decode_legacy_addr_after_marker(bl); + return; + } + if (marker != 1) + throw ceph::buffer::malformed_input("entity_addr_t marker != 1"); + DECODE_START(1, bl); + decode(type, bl); + decode(nonce, bl); + __u32 elen; + decode(elen, bl); + if (elen) { +#if defined(__FreeBSD__) || defined(__APPLE__) + u.sa.sa_len = 0; +#endif + uint16_t ss_family; + if (elen < sizeof(ss_family)) { + throw ceph::buffer::malformed_input("elen smaller than family len"); + } + decode(ss_family, bl); +#if defined(_WIN32) + if (ss_family == AF_INET6_LINUX) { + ss_family = AF_INET6; + } +#endif + u.sa.sa_family = ss_family; + elen -= sizeof(ss_family); + if (elen > get_sockaddr_len() - sizeof(u.sa.sa_family)) { + throw ceph::buffer::malformed_input("elen exceeds sockaddr len"); + } + bl.copy(elen, u.sa.sa_data); + } + DECODE_FINISH(bl); + } + + void dump(ceph::Formatter *f) const; + + static void generate_test_instances(std::list<entity_addr_t*>& o); +}; +WRITE_CLASS_ENCODER_FEATURES(entity_addr_t) + +std::ostream& operator<<(std::ostream& out, const entity_addr_t &addr); + +inline bool operator==(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) == 0; } +inline bool operator!=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) != 0; } +inline bool operator<(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) < 0; } +inline bool operator<=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) <= 0; } +inline bool operator>(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) > 0; } +inline bool operator>=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) >= 0; } + +namespace std { +template<> struct hash<entity_addr_t> { + size_t operator()( const entity_addr_t& x ) const { + static blobhash H; + return H(&x, sizeof(x)); + } +}; +} // namespace std + +struct entity_addrvec_t { + std::vector<entity_addr_t> v; + + entity_addrvec_t() {} + explicit entity_addrvec_t(const entity_addr_t& a) : v({ a }) {} + + unsigned size() const { return v.size(); } + bool empty() const { return v.empty(); } + + entity_addr_t legacy_addr() const { + return addr_of_type(entity_addr_t::TYPE_LEGACY); + } + entity_addr_t as_legacy_addr() const { + for (auto& a : v) { + if (a.is_legacy()) { + return a; + } + if (a.is_any()) { + auto b = a; + b.set_type(entity_addr_t::TYPE_LEGACY); + return b; + } + } + // hrm... lie! + auto a = front(); + a.set_type(entity_addr_t::TYPE_LEGACY); + return a; + } + entity_addr_t front() const { + if (!v.empty()) { + return v.front(); + } + return entity_addr_t(); + } + entity_addr_t legacy_or_front_addr() const { + for (auto& a : v) { + if (a.type == entity_addr_t::TYPE_LEGACY) { + return a; + } + } + return front(); + } + std::string get_legacy_str() const { + return legacy_or_front_addr().get_legacy_str(); + } + + entity_addr_t msgr2_addr() const { + return addr_of_type(entity_addr_t::TYPE_MSGR2); + } + bool has_msgr2() const { + for (auto& a : v) { + if (a.is_msgr2()) { + return true; + } + } + return false; + } + + entity_addr_t pick_addr(uint32_t type) const { + entity_addr_t picked_addr; + switch (type) { + case entity_addr_t::TYPE_LEGACY: + [[fallthrough]]; + case entity_addr_t::TYPE_MSGR2: + picked_addr = addr_of_type(type); + break; + case entity_addr_t::TYPE_ANY: + return front(); + default: + return {}; + } + if (!picked_addr.is_blank_ip()) { + return picked_addr; + } else { + return addr_of_type(entity_addr_t::TYPE_ANY); + } + } + + entity_addr_t addr_of_type(uint32_t type) const { + for (auto &a : v) { + if (a.type == type) { + return a; + } + } + return entity_addr_t(); + } + + bool parse(const char *s, const char **end = 0); + + void get_ports(std::set<int> *ports) const { + for (auto& a : v) { + ports->insert(a.get_port()); + } + } + std::set<int> get_ports() const { + std::set<int> r; + get_ports(&r); + return r; + } + + void encode(ceph::buffer::list& bl, uint64_t features) const; + void decode(ceph::buffer::list::const_iterator& bl); + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list<entity_addrvec_t*>& ls); + + bool legacy_equals(const entity_addrvec_t& o) const { + if (v == o.v) { + return true; + } + if (v.size() == 1 && + front().is_legacy() && + front() == o.legacy_addr()) { + return true; + } + if (o.v.size() == 1 && + o.front().is_legacy() && + o.front() == legacy_addr()) { + return true; + } + return false; + } + + bool probably_equals(const entity_addrvec_t& o) const { + for (unsigned i = 0; i < v.size(); ++i) { + if (!v[i].probably_equals(o.v[i])) { + return false; + } + } + return true; + } + bool contains(const entity_addr_t& a) const { + for (auto& i : v) { + if (a == i) { + return true; + } + } + return false; + } + bool is_same_host(const entity_addr_t& a) const { + for (auto& i : v) { + if (i.is_same_host(a)) { + return true; + } + } + return false; + } + + friend std::ostream& operator<<(std::ostream& out, const entity_addrvec_t& av) { + if (av.v.empty()) { + return out; + } else if (av.v.size() == 1) { + return out << av.v[0]; + } else { + return out << av.v; + } + } + + friend bool operator==(const entity_addrvec_t& l, const entity_addrvec_t& r) { + return l.v == r.v; + } + friend bool operator!=(const entity_addrvec_t& l, const entity_addrvec_t& r) { + return l.v != r.v; + } + friend bool operator<(const entity_addrvec_t& l, const entity_addrvec_t& r) { + return l.v < r.v; // see lexicographical_compare() + } +}; +WRITE_CLASS_ENCODER_FEATURES(entity_addrvec_t); + +namespace std { +template<> struct hash<entity_addrvec_t> { + size_t operator()( const entity_addrvec_t& x) const { + static blobhash H; + size_t r = 0; + for (auto& i : x.v) { + r += H((const char*)&i, sizeof(i)); + } + return r; + } +}; +} // namespace std + +/* + * a particular entity instance + */ +struct entity_inst_t { + entity_name_t name; + entity_addr_t addr; + entity_inst_t() {} + entity_inst_t(entity_name_t n, const entity_addr_t& a) : name(n), addr(a) {} + // cppcheck-suppress noExplicitConstructor + entity_inst_t(const ceph_entity_inst& i) : name(i.name), addr(i.addr) { } + entity_inst_t(const ceph_entity_name& n, const ceph_entity_addr &a) : name(n), addr(a) {} + operator ceph_entity_inst() { + ceph_entity_inst i = {name, addr}; + return i; + } + + void encode(ceph::buffer::list& bl, uint64_t features) const { + using ceph::encode; + encode(name, bl); + encode(addr, bl, features); + } + void decode(ceph::buffer::list::const_iterator& bl) { + using ceph::decode; + decode(name, bl); + decode(addr, bl); + } + + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list<entity_inst_t*>& o); +}; +WRITE_CLASS_ENCODER_FEATURES(entity_inst_t) + + +inline bool operator==(const entity_inst_t& a, const entity_inst_t& b) { + return a.name == b.name && a.addr == b.addr; +} +inline bool operator!=(const entity_inst_t& a, const entity_inst_t& b) { + return a.name != b.name || a.addr != b.addr; +} +inline bool operator<(const entity_inst_t& a, const entity_inst_t& b) { + return a.name < b.name || (a.name == b.name && a.addr < b.addr); +} +inline bool operator<=(const entity_inst_t& a, const entity_inst_t& b) { + return a.name < b.name || (a.name == b.name && a.addr <= b.addr); +} +inline bool operator>(const entity_inst_t& a, const entity_inst_t& b) { return b < a; } +inline bool operator>=(const entity_inst_t& a, const entity_inst_t& b) { return b <= a; } + +namespace std { + template<> struct hash< entity_inst_t > + { + size_t operator()( const entity_inst_t& x ) const + { + static hash< entity_name_t > H; + static hash< entity_addr_t > I; + return H(x.name) ^ I(x.addr); + } + }; +} // namespace std + + +inline std::ostream& operator<<(std::ostream& out, const entity_inst_t &i) +{ + return out << i.name << " " << i.addr; +} +inline std::ostream& operator<<(std::ostream& out, const ceph_entity_inst &i) +{ + entity_inst_t n = i; + return out << n; +} + +#endif |