1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #ifndef CEPH_MSG_TYPES_H
16 #define CEPH_MSG_TYPES_H
20 #include <netinet/in.h>
21 #include <fmt/format.h>
22 #if FMT_VERSION >= 90000
23 #include <fmt/ostream.h>
26 #include "include/ceph_features.h"
27 #include "include/types.h"
28 #include "include/blobhash.h"
29 #include "include/encoding.h"
31 #define MAX_PORT_NUMBER 65535
34 // ceph_sockaddr_storage matches the Linux format.
35 #define AF_INET6_LINUX 10
42 std::ostream
& operator<<(std::ostream
& out
, const sockaddr_storage
&ss
);
43 std::ostream
& operator<<(std::ostream
& out
, const sockaddr
*sa
);
45 typedef uint8_t entity_type_t
;
53 static const int TYPE_MON
= CEPH_ENTITY_TYPE_MON
;
54 static const int TYPE_MDS
= CEPH_ENTITY_TYPE_MDS
;
55 static const int TYPE_OSD
= CEPH_ENTITY_TYPE_OSD
;
56 static const int TYPE_CLIENT
= CEPH_ENTITY_TYPE_CLIENT
;
57 static const int TYPE_MGR
= CEPH_ENTITY_TYPE_MGR
;
59 static const int64_t NEW
= -1;
62 entity_name_t() : _type(0), _num(0) { }
63 entity_name_t(int t
, int64_t n
) : _type(t
), _num(n
) { }
64 explicit entity_name_t(const ceph_entity_name
&n
) :
65 _type(n
.type
), _num(n
.num
) { }
68 static entity_name_t
MON(int64_t i
=NEW
) { return entity_name_t(TYPE_MON
, i
); }
69 static entity_name_t
MDS(int64_t i
=NEW
) { return entity_name_t(TYPE_MDS
, i
); }
70 static entity_name_t
OSD(int64_t i
=NEW
) { return entity_name_t(TYPE_OSD
, i
); }
71 static entity_name_t
CLIENT(int64_t i
=NEW
) { return entity_name_t(TYPE_CLIENT
, i
); }
72 static entity_name_t
MGR(int64_t i
=NEW
) { return entity_name_t(TYPE_MGR
, i
); }
74 int64_t num() const { return _num
; }
75 int type() const { return _type
; }
76 const char *type_str() const {
77 return ceph_entity_type_name(type());
80 bool is_new() const { return num() < 0; }
82 bool is_client() const { return type() == TYPE_CLIENT
; }
83 bool is_mds() const { return type() == TYPE_MDS
; }
84 bool is_osd() const { return type() == TYPE_OSD
; }
85 bool is_mon() const { return type() == TYPE_MON
; }
86 bool is_mgr() const { return type() == TYPE_MGR
; }
88 operator ceph_entity_name() const {
89 ceph_entity_name n
= { _type
, ceph_le64(_num
) };
93 bool parse(std::string_view s
);
95 DENC(entity_name_t
, v
, p
) {
99 void dump(ceph::Formatter
*f
) const;
101 static void generate_test_instances(std::list
<entity_name_t
*>& o
);
103 WRITE_CLASS_DENC(entity_name_t
)
105 inline bool operator== (const entity_name_t
& l
, const entity_name_t
& r
) {
106 return (l
.type() == r
.type()) && (l
.num() == r
.num()); }
107 inline bool operator!= (const entity_name_t
& l
, const entity_name_t
& r
) {
108 return (l
.type() != r
.type()) || (l
.num() != r
.num()); }
109 inline bool operator< (const entity_name_t
& l
, const entity_name_t
& r
) {
110 return (l
.type() < r
.type()) || (l
.type() == r
.type() && l
.num() < r
.num()); }
112 inline std::ostream
& operator<<(std::ostream
& out
, const entity_name_t
& addr
) {
113 //if (addr.is_namer()) return out << "namer";
114 if (addr
.is_new() || addr
.num() < 0)
115 return out
<< addr
.type_str() << ".?";
117 return out
<< addr
.type_str() << '.' << addr
.num();
119 inline std::ostream
& operator<<(std::ostream
& out
, const ceph_entity_name
& addr
) {
120 return out
<< entity_name_t
{addr
.type
, static_cast<int64_t>(addr
.num
)};
124 template<> struct hash
< entity_name_t
>
126 size_t operator()( const entity_name_t
&m
) const
128 return rjhash32(m
.type() ^ m
.num());
133 // define a wire format for sockaddr that matches Linux's.
134 struct ceph_sockaddr_storage
{
136 __u8 __ss_padding
[128 - sizeof(ceph_le16
)];
138 void encode(ceph::buffer::list
& bl
) const {
139 struct ceph_sockaddr_storage ss
= *this;
140 ss
.ss_family
= htons(ss
.ss_family
);
141 ceph::encode_raw(ss
, bl
);
144 void decode(ceph::buffer::list::const_iterator
& bl
) {
145 struct ceph_sockaddr_storage ss
;
146 ceph::decode_raw(ss
, bl
);
147 ss
.ss_family
= ntohs(ss
.ss_family
);
150 } __attribute__ ((__packed__
));
151 WRITE_CLASS_ENCODER(ceph_sockaddr_storage
)
154 * encode sockaddr.ss_family as network byte order
156 static inline void encode(const sockaddr_storage
& a
, ceph::buffer::list
& bl
) {
157 #if defined(__linux__)
158 struct sockaddr_storage ss
= a
;
159 ss
.ss_family
= htons(ss
.ss_family
);
160 ceph::encode_raw(ss
, bl
);
161 #elif defined(__FreeBSD__) || defined(__APPLE__)
162 ceph_sockaddr_storage ss
{};
163 auto src
= (unsigned char const *)&a
;
164 auto dst
= (unsigned char *)&ss
;
165 src
+= sizeof(a
.ss_len
);
166 ss
.ss_family
= a
.ss_family
;
167 src
+= sizeof(a
.ss_family
);
168 dst
+= sizeof(ss
.ss_family
);
169 const auto copy_size
= std::min((unsigned char*)(&a
+ 1) - src
,
170 (unsigned char*)(&ss
+ 1) - dst
);
171 ::memcpy(dst
, src
, copy_size
);
173 #elif defined(_WIN32)
174 ceph_sockaddr_storage ss
{};
175 ::memcpy(&ss
, &a
, std::min(sizeof(ss
), sizeof(a
)));
176 // The Windows AF_INET6 definition doesn't match the Linux one.
177 if (a
.ss_family
== AF_INET6
) {
178 ss
.ss_family
= AF_INET6_LINUX
;
182 ceph_sockaddr_storage ss
;
183 ::memset(&ss
, '\0', sizeof(ss
));
184 ::memcpy(&ss
, &a
, std::min(sizeof(ss
), sizeof(a
)));
188 static inline void decode(sockaddr_storage
& a
,
189 ceph::buffer::list::const_iterator
& bl
) {
190 #if defined(__linux__)
191 ceph::decode_raw(a
, bl
);
192 a
.ss_family
= ntohs(a
.ss_family
);
193 #elif defined(__FreeBSD__) || defined(__APPLE__)
194 ceph_sockaddr_storage ss
{};
196 auto src
= (unsigned char const *)&ss
;
197 auto dst
= (unsigned char *)&a
;
199 dst
+= sizeof(a
.ss_len
);
200 a
.ss_family
= ss
.ss_family
;
201 src
+= sizeof(ss
.ss_family
);
202 dst
+= sizeof(a
.ss_family
);
203 auto const copy_size
= std::min((unsigned char*)(&ss
+ 1) - src
,
204 (unsigned char*)(&a
+ 1) - dst
);
205 ::memcpy(dst
, src
, copy_size
);
206 #elif defined(_WIN32)
207 ceph_sockaddr_storage ss
{};
209 ::memcpy(&a
, &ss
, std::min(sizeof(ss
), sizeof(a
)));
210 if (a
.ss_family
== AF_INET6_LINUX
) {
211 a
.ss_family
= AF_INET6
;
214 ceph_sockaddr_storage ss
{};
216 ::memcpy(&a
, &ss
, std::min(sizeof(ss
), sizeof(a
)));
221 * an entity's network address.
222 * includes a random value that prevents it from being reused.
223 * thus identifies a particular process instance.
225 * This also happens to work to support cidr ranges, in which
226 * case the nonce contains the netmask. It's great!
228 struct entity_addr_t
{
231 TYPE_LEGACY
= 1, ///< legacy msgr1 protocol (ceph jewel and older)
232 TYPE_MSGR2
= 2, ///< msgr2 protocol (new in ceph kraken)
233 TYPE_ANY
= 3, ///< ambiguous
236 static const type_t TYPE_DEFAULT
= TYPE_MSGR2
;
237 static std::string_view
get_type_name(int t
) {
239 case TYPE_NONE
: return "none";
240 case TYPE_LEGACY
: return "v1";
241 case TYPE_MSGR2
: return "v2";
242 case TYPE_ANY
: return "any";
243 case TYPE_CIDR
: return "cidr";
244 default: return "???";
256 entity_addr_t() : type(0), nonce(0) {
257 memset(&u
, 0, sizeof(u
));
259 entity_addr_t(__u32 _type
, __u32 _nonce
) : type(_type
), nonce(_nonce
) {
260 memset(&u
, 0, sizeof(u
));
262 explicit entity_addr_t(const ceph_entity_addr
&o
) {
265 memcpy(&u
, &o
.in_addr
, sizeof(u
));
266 #if !defined(__FreeBSD__)
267 u
.sa
.sa_family
= ntohs(u
.sa
.sa_family
);
271 uint32_t get_type() const { return type
; }
272 void set_type(uint32_t t
) { type
= t
; }
273 bool is_legacy() const { return type
== TYPE_LEGACY
; }
274 bool is_msgr2() const { return type
== TYPE_MSGR2
; }
275 bool is_any() const { return type
== TYPE_ANY
; }
276 // this isn't a guarantee; some client addrs will match it
277 bool maybe_cidr() const { return get_port() == 0 && nonce
!= 0; }
279 __u32
get_nonce() const { return nonce
; }
280 void set_nonce(__u32 n
) { nonce
= n
; }
282 int get_family() const {
283 return u
.sa
.sa_family
;
285 void set_family(int f
) {
289 bool is_ipv4() const {
290 return u
.sa
.sa_family
== AF_INET
;
292 bool is_ipv6() const {
293 return u
.sa
.sa_family
== AF_INET6
;
296 sockaddr_in
&in4_addr() {
299 const sockaddr_in
&in4_addr() const{
302 sockaddr_in6
&in6_addr(){
305 const sockaddr_in6
&in6_addr() const{
308 const sockaddr
*get_sockaddr() const {
311 size_t get_sockaddr_len() const {
312 switch (u
.sa
.sa_family
) {
314 return sizeof(u
.sin
);
316 return sizeof(u
.sin6
);
320 bool set_sockaddr(const struct sockaddr
*sa
)
322 switch (sa
->sa_family
) {
324 // pre-zero, since we're only copying a portion of the source
325 memset(&u
, 0, sizeof(u
));
326 memcpy(&u
.sin
, sa
, sizeof(u
.sin
));
329 // pre-zero, since we're only copying a portion of the source
330 memset(&u
, 0, sizeof(u
));
331 memcpy(&u
.sin6
, sa
, sizeof(u
.sin6
));
334 memset(&u
, 0, sizeof(u
));
342 sockaddr_storage
get_sockaddr_storage() const {
344 memcpy(&ss
, &u
, sizeof(u
));
345 memset((char*)&ss
+ sizeof(u
), 0, sizeof(ss
) - sizeof(u
));
349 void set_in4_quad(int pos
, int val
) {
350 u
.sin
.sin_family
= AF_INET
;
351 unsigned char *ipq
= (unsigned char*)&u
.sin
.sin_addr
.s_addr
;
354 void set_port(int port
) {
355 switch (u
.sa
.sa_family
) {
357 u
.sin
.sin_port
= htons(port
);
360 u
.sin6
.sin6_port
= htons(port
);
366 int get_port() const {
367 switch (u
.sa
.sa_family
) {
369 return ntohs(u
.sin
.sin_port
);
371 return ntohs(u
.sin6
.sin6_port
);
376 operator ceph_entity_addr() const {
380 a
.in_addr
= get_sockaddr_storage();
381 #if !defined(__FreeBSD__)
382 a
.in_addr
.ss_family
= htons(a
.in_addr
.ss_family
);
387 bool probably_equals(const entity_addr_t
&o
) const {
388 if (get_port() != o
.get_port())
390 if (get_nonce() != o
.get_nonce())
392 if (is_blank_ip() || o
.is_blank_ip())
394 if (memcmp(&u
, &o
.u
, sizeof(u
)) == 0)
399 bool is_same_host(const entity_addr_t
&o
) const {
400 if (u
.sa
.sa_family
!= o
.u
.sa
.sa_family
)
402 if (u
.sa
.sa_family
== AF_INET
)
403 return u
.sin
.sin_addr
.s_addr
== o
.u
.sin
.sin_addr
.s_addr
;
404 if (u
.sa
.sa_family
== AF_INET6
)
405 return memcmp(u
.sin6
.sin6_addr
.s6_addr
,
406 o
.u
.sin6
.sin6_addr
.s6_addr
,
407 sizeof(u
.sin6
.sin6_addr
.s6_addr
)) == 0;
411 bool is_blank_ip() const {
412 switch (u
.sa
.sa_family
) {
414 return u
.sin
.sin_addr
.s_addr
== INADDR_ANY
;
416 return memcmp(&u
.sin6
.sin6_addr
, &in6addr_any
, sizeof(in6addr_any
)) == 0;
423 switch (u
.sa
.sa_family
) {
432 std::string
ip_only_to_str() const;
433 std::string
ip_n_port_to_str() const;
435 std::string
get_legacy_str() const {
436 std::ostringstream ss
;
437 ss
<< get_sockaddr() << "/" << get_nonce();
441 bool parse(const std::string_view s
, int default_type
=TYPE_DEFAULT
);
442 bool parse(const char *s
, const char **end
= 0, int default_type
=TYPE_DEFAULT
);
444 void decode_legacy_addr_after_marker(ceph::buffer::list::const_iterator
& bl
)
454 set_sockaddr((sockaddr
*)&ss
);
455 if (get_family() == AF_UNSPEC
) {
462 // Right now, these only deal with sockaddr_storage that have only family and content.
463 // Apparently on BSD there is also an ss_len that we need to handle; this requires
466 void encode(ceph::buffer::list
& bl
, uint64_t features
) const {
468 if ((features
& CEPH_FEATURE_MSG_ADDR2
) == 0) {
469 encode((__u32
)0, bl
);
471 sockaddr_storage ss
= get_sockaddr_storage();
476 ENCODE_START(1, 1, bl
);
477 if (HAVE_FEATURE(features
, SERVER_NAUTILUS
)) {
480 // map any -> legacy for old clients. this is primary for the benefit
481 // of OSDMap's blocklist, but is reasonable in general since any: is
482 // meaningless for pre-nautilus clients or daemons.
490 __u32 elen
= get_sockaddr_len();
491 #if (__FreeBSD__) || defined(__APPLE__)
492 elen
-= sizeof(u
.sa
.sa_len
);
496 uint16_t ss_family
= u
.sa
.sa_family
;
498 if (ss_family
== AF_INET6
) {
499 ss_family
= AF_INET6_LINUX
;
502 encode(ss_family
, bl
);
503 elen
-= sizeof(u
.sa
.sa_family
);
504 bl
.append(u
.sa
.sa_data
, elen
);
508 void decode(ceph::buffer::list::const_iterator
& bl
) {
513 decode_legacy_addr_after_marker(bl
);
517 throw ceph::buffer::malformed_input("entity_addr_t marker != 1");
524 #if defined(__FreeBSD__) || defined(__APPLE__)
528 if (elen
< sizeof(ss_family
)) {
529 throw ceph::buffer::malformed_input("elen smaller than family len");
531 decode(ss_family
, bl
);
533 if (ss_family
== AF_INET6_LINUX
) {
534 ss_family
= AF_INET6
;
537 u
.sa
.sa_family
= ss_family
;
538 elen
-= sizeof(ss_family
);
539 if (elen
> get_sockaddr_len() - sizeof(u
.sa
.sa_family
)) {
540 throw ceph::buffer::malformed_input("elen exceeds sockaddr len");
542 bl
.copy(elen
, u
.sa
.sa_data
);
547 void dump(ceph::Formatter
*f
) const;
549 static void generate_test_instances(std::list
<entity_addr_t
*>& o
);
551 WRITE_CLASS_ENCODER_FEATURES(entity_addr_t
)
553 std::ostream
& operator<<(std::ostream
& out
, const entity_addr_t
&addr
);
554 #if FMT_VERSION >= 90000
555 template <> struct fmt::formatter
<entity_addr_t
> : fmt::ostream_formatter
{};
558 inline bool operator==(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) == 0; }
559 inline bool operator!=(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) != 0; }
560 inline bool operator<(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) < 0; }
561 inline bool operator<=(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) <= 0; }
562 inline bool operator>(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) > 0; }
563 inline bool operator>=(const entity_addr_t
& a
, const entity_addr_t
& b
) { return memcmp(&a
, &b
, sizeof(a
)) >= 0; }
566 template<> struct hash
<entity_addr_t
> {
567 size_t operator()( const entity_addr_t
& x
) const {
569 return H(&x
, sizeof(x
));
574 struct entity_addrvec_t
{
575 std::vector
<entity_addr_t
> v
;
577 entity_addrvec_t() {}
578 explicit entity_addrvec_t(const entity_addr_t
& a
) : v({ a
}) {}
580 unsigned size() const { return v
.size(); }
581 bool empty() const { return v
.empty(); }
583 entity_addr_t
legacy_addr() const {
584 return addr_of_type(entity_addr_t::TYPE_LEGACY
);
586 entity_addr_t
as_legacy_addr() const {
593 b
.set_type(entity_addr_t::TYPE_LEGACY
);
599 a
.set_type(entity_addr_t::TYPE_LEGACY
);
602 entity_addr_t
front() const {
606 return entity_addr_t();
608 entity_addr_t
legacy_or_front_addr() const {
610 if (a
.type
== entity_addr_t::TYPE_LEGACY
) {
616 std::string
get_legacy_str() const {
617 return legacy_or_front_addr().get_legacy_str();
620 entity_addr_t
msgr2_addr() const {
621 return addr_of_type(entity_addr_t::TYPE_MSGR2
);
623 bool has_msgr2() const {
632 entity_addr_t
pick_addr(uint32_t type
) const {
633 entity_addr_t picked_addr
;
635 case entity_addr_t::TYPE_LEGACY
:
637 case entity_addr_t::TYPE_MSGR2
:
638 picked_addr
= addr_of_type(type
);
640 case entity_addr_t::TYPE_ANY
:
645 if (!picked_addr
.is_blank_ip()) {
648 return addr_of_type(entity_addr_t::TYPE_ANY
);
652 entity_addr_t
addr_of_type(uint32_t type
) const {
654 if (a
.type
== type
) {
658 return entity_addr_t();
661 bool parse(const char *s
, const char **end
= 0);
663 void get_ports(std::set
<int> *ports
) const {
665 ports
->insert(a
.get_port());
668 std::set
<int> get_ports() const {
674 void encode(ceph::buffer::list
& bl
, uint64_t features
) const;
675 void decode(ceph::buffer::list::const_iterator
& bl
);
676 void dump(ceph::Formatter
*f
) const;
677 static void generate_test_instances(std::list
<entity_addrvec_t
*>& ls
);
679 bool legacy_equals(const entity_addrvec_t
& o
) const {
684 front().is_legacy() &&
685 front() == o
.legacy_addr()) {
688 if (o
.v
.size() == 1 &&
689 o
.front().is_legacy() &&
690 o
.front() == legacy_addr()) {
696 bool probably_equals(const entity_addrvec_t
& o
) const {
697 for (unsigned i
= 0; i
< v
.size(); ++i
) {
698 if (!v
[i
].probably_equals(o
.v
[i
])) {
704 bool contains(const entity_addr_t
& a
) const {
712 bool is_same_host(const entity_addr_t
& a
) const {
714 if (i
.is_same_host(a
)) {
721 friend std::ostream
& operator<<(std::ostream
& out
, const entity_addrvec_t
& av
) {
724 } else if (av
.v
.size() == 1) {
725 return out
<< av
.v
[0];
731 friend bool operator==(const entity_addrvec_t
& l
, const entity_addrvec_t
& r
) {
734 friend bool operator!=(const entity_addrvec_t
& l
, const entity_addrvec_t
& r
) {
737 friend bool operator<(const entity_addrvec_t
& l
, const entity_addrvec_t
& r
) {
738 return l
.v
< r
.v
; // see lexicographical_compare()
740 friend bool operator>(const entity_addrvec_t
& l
, const entity_addrvec_t
& r
) {
741 return l
.v
> r
.v
; // see lexicographical_compare()
744 WRITE_CLASS_ENCODER_FEATURES(entity_addrvec_t
);
745 #if FMT_VERSION >= 90000
746 template <> struct fmt::formatter
<entity_addrvec_t
> : fmt::ostream_formatter
{};
750 template<> struct hash
<entity_addrvec_t
> {
751 size_t operator()( const entity_addrvec_t
& x
) const {
754 for (auto& i
: x
.v
) {
755 r
+= H((const char*)&i
, sizeof(i
));
763 * a particular entity instance
765 struct entity_inst_t
{
769 entity_inst_t(entity_name_t n
, const entity_addr_t
& a
) : name(n
), addr(a
) {}
770 // cppcheck-suppress noExplicitConstructor
771 entity_inst_t(const ceph_entity_inst
& i
) : name(i
.name
), addr(i
.addr
) { }
772 entity_inst_t(const ceph_entity_name
& n
, const ceph_entity_addr
&a
) : name(n
), addr(a
) {}
773 operator ceph_entity_inst() {
774 ceph_entity_inst i
= {name
, addr
};
778 void encode(ceph::buffer::list
& bl
, uint64_t features
) const {
781 encode(addr
, bl
, features
);
783 void decode(ceph::buffer::list::const_iterator
& bl
) {
789 void dump(ceph::Formatter
*f
) const;
790 static void generate_test_instances(std::list
<entity_inst_t
*>& o
);
792 WRITE_CLASS_ENCODER_FEATURES(entity_inst_t
)
795 inline bool operator==(const entity_inst_t
& a
, const entity_inst_t
& b
) {
796 return a
.name
== b
.name
&& a
.addr
== b
.addr
;
798 inline bool operator!=(const entity_inst_t
& a
, const entity_inst_t
& b
) {
799 return a
.name
!= b
.name
|| a
.addr
!= b
.addr
;
801 inline bool operator<(const entity_inst_t
& a
, const entity_inst_t
& b
) {
802 return a
.name
< b
.name
|| (a
.name
== b
.name
&& a
.addr
< b
.addr
);
804 inline bool operator<=(const entity_inst_t
& a
, const entity_inst_t
& b
) {
805 return a
.name
< b
.name
|| (a
.name
== b
.name
&& a
.addr
<= b
.addr
);
807 inline bool operator>(const entity_inst_t
& a
, const entity_inst_t
& b
) { return b
< a
; }
808 inline bool operator>=(const entity_inst_t
& a
, const entity_inst_t
& b
) { return b
<= a
; }
811 template<> struct hash
< entity_inst_t
>
813 size_t operator()( const entity_inst_t
& x
) const
815 static hash
< entity_name_t
> H
;
816 static hash
< entity_addr_t
> I
;
817 return H(x
.name
) ^ I(x
.addr
);
823 inline std::ostream
& operator<<(std::ostream
& out
, const entity_inst_t
&i
)
825 return out
<< i
.name
<< " " << i
.addr
;
827 inline std::ostream
& operator<<(std::ostream
& out
, const ceph_entity_inst
&i
)