1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
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.
12 *
13 */
14
15 #ifndef CEPH_MSG_TYPES_H
16 #define CEPH_MSG_TYPES_H
17
18 #include <sstream>
19
20 #include <netinet/in.h>
21
22 #include "include/ceph_features.h"
23 #include "include/types.h"
24 #include "include/blobhash.h"
25 #include "include/encoding.h"
26
27 #define MAX_PORT_NUMBER 65535
28
29 namespace ceph {
30 class Formatter;
31 }
32
33 std::ostream& operator<<(std::ostream& out, const sockaddr_storage &ss);
34 std::ostream& operator<<(std::ostream& out, const sockaddr *sa);
35
36 typedef uint8_t entity_type_t;
37
38 class entity_name_t {
39 public:
40 entity_type_t _type;
41 int64_t _num;
42
43 public:
44 static const int TYPE_MON = CEPH_ENTITY_TYPE_MON;
45 static const int TYPE_MDS = CEPH_ENTITY_TYPE_MDS;
46 static const int TYPE_OSD = CEPH_ENTITY_TYPE_OSD;
47 static const int TYPE_CLIENT = CEPH_ENTITY_TYPE_CLIENT;
48 static const int TYPE_MGR = CEPH_ENTITY_TYPE_MGR;
49
50 static const int64_t NEW = -1;
51
52 // cons
53 entity_name_t() : _type(0), _num(0) { }
54 entity_name_t(int t, int64_t n) : _type(t), _num(n) { }
55 explicit entity_name_t(const ceph_entity_name &n) :
56 _type(n.type), _num(n.num) { }
57
58 // static cons
59 static entity_name_t MON(int64_t i=NEW) { return entity_name_t(TYPE_MON, i); }
60 static entity_name_t MDS(int64_t i=NEW) { return entity_name_t(TYPE_MDS, i); }
61 static entity_name_t OSD(int64_t i=NEW) { return entity_name_t(TYPE_OSD, i); }
62 static entity_name_t CLIENT(int64_t i=NEW) { return entity_name_t(TYPE_CLIENT, i); }
63 static entity_name_t MGR(int64_t i=NEW) { return entity_name_t(TYPE_MGR, i); }
64
65 int64_t num() const { return _num; }
66 int type() const { return _type; }
67 const char *type_str() const {
68 return ceph_entity_type_name(type());
69 }
70
71 bool is_new() const { return num() < 0; }
72
73 bool is_client() const { return type() == TYPE_CLIENT; }
74 bool is_mds() const { return type() == TYPE_MDS; }
75 bool is_osd() const { return type() == TYPE_OSD; }
76 bool is_mon() const { return type() == TYPE_MON; }
77 bool is_mgr() const { return type() == TYPE_MGR; }
78
79 operator ceph_entity_name() const {
80 ceph_entity_name n = { _type, init_le64(_num) };
81 return n;
82 }
83
84 bool parse(const std::string& s) {
85 const char *start = s.c_str();
86 char *end;
87 bool got = parse(start, &end);
88 return got && end == start + s.length();
89 }
90 bool parse(const char *start, char **end) {
91 if (strstr(start, "mon.") == start) {
92 _type = TYPE_MON;
93 start += 4;
94 } else if (strstr(start, "osd.") == start) {
95 _type = TYPE_OSD;
96 start += 4;
97 } else if (strstr(start, "mds.") == start) {
98 _type = TYPE_MDS;
99 start += 4;
100 } else if (strstr(start, "client.") == start) {
101 _type = TYPE_CLIENT;
102 start += 7;
103 } else if (strstr(start, "mgr.") == start) {
104 _type = TYPE_MGR;
105 start += 4;
106 } else {
107 return false;
108 }
109 if (isspace(*start))
110 return false;
111 _num = strtoll(start, end, 10);
112 if (*end == NULL || *end == start)
113 return false;
114 return true;
115 }
116
117 DENC(entity_name_t, v, p) {
118 denc(v._type, p);
119 denc(v._num, p);
120 }
121 void dump(ceph::Formatter *f) const;
122
123 static void generate_test_instances(std::list<entity_name_t*>& o);
124 };
125 WRITE_CLASS_DENC(entity_name_t)
126
127 inline bool operator== (const entity_name_t& l, const entity_name_t& r) {
128 return (l.type() == r.type()) && (l.num() == r.num()); }
129 inline bool operator!= (const entity_name_t& l, const entity_name_t& r) {
130 return (l.type() != r.type()) || (l.num() != r.num()); }
131 inline bool operator< (const entity_name_t& l, const entity_name_t& r) {
132 return (l.type() < r.type()) || (l.type() == r.type() && l.num() < r.num()); }
133
134 inline std::ostream& operator<<(std::ostream& out, const entity_name_t& addr) {
135 //if (addr.is_namer()) return out << "namer";
136 if (addr.is_new() || addr.num() < 0)
137 return out << addr.type_str() << ".?";
138 else
139 return out << addr.type_str() << '.' << addr.num();
140 }
141 inline std::ostream& operator<<(std::ostream& out, const ceph_entity_name& addr) {
142 return out << entity_name_t{addr.type, static_cast<int64_t>(addr.num)};
143 }
144
145 namespace std {
146 template<> struct hash< entity_name_t >
147 {
148 size_t operator()( const entity_name_t &m ) const
149 {
150 return rjhash32(m.type() ^ m.num());
151 }
152 };
153 } // namespace std
154
155 // define a wire format for sockaddr that matches Linux's.
156 struct ceph_sockaddr_storage {
157 ceph_le16 ss_family;
158 __u8 __ss_padding[128 - sizeof(ceph_le16)];
159
160 void encode(ceph::buffer::list& bl) const {
161 struct ceph_sockaddr_storage ss = *this;
162 ss.ss_family = htons(ss.ss_family);
163 ceph::encode_raw(ss, bl);
164 }
165
166 void decode(ceph::buffer::list::const_iterator& bl) {
167 struct ceph_sockaddr_storage ss;
168 ceph::decode_raw(ss, bl);
169 ss.ss_family = ntohs(ss.ss_family);
170 *this = ss;
171 }
172 } __attribute__ ((__packed__));
173 WRITE_CLASS_ENCODER(ceph_sockaddr_storage)
174
175 /*
176 * encode sockaddr.ss_family as network byte order
177 */
178 static inline void encode(const sockaddr_storage& a, ceph::buffer::list& bl) {
179 #if defined(__linux__)
180 struct sockaddr_storage ss = a;
181 ss.ss_family = htons(ss.ss_family);
182 ceph::encode_raw(ss, bl);
183 #elif defined(__FreeBSD__) || defined(__APPLE__)
184 ceph_sockaddr_storage ss{};
185 auto src = (unsigned char const *)&a;
186 auto dst = (unsigned char *)&ss;
187 src += sizeof(a.ss_len);
188 ss.ss_family = a.ss_family;
189 src += sizeof(a.ss_family);
190 dst += sizeof(ss.ss_family);
191 const auto copy_size = std::min((unsigned char*)(&a + 1) - src,
192 (unsigned char*)(&ss + 1) - dst);
193 ::memcpy(dst, src, copy_size);
194 encode(ss, bl);
195 #else
196 ceph_sockaddr_storage ss{};
197 ::memset(&ss, '\0', sizeof(ss));
198 ::memcpy(&wireaddr, &ss, std::min(sizeof(ss), sizeof(a)));
199 encode(ss, bl);
200 #endif
201 }
202 static inline void decode(sockaddr_storage& a,
203 ceph::buffer::list::const_iterator& bl) {
204 #if defined(__linux__)
205 ceph::decode_raw(a, bl);
206 a.ss_family = ntohs(a.ss_family);
207 #elif defined(__FreeBSD__) || defined(__APPLE__)
208 ceph_sockaddr_storage ss{};
209 decode(ss, bl);
210 auto src = (unsigned char const *)&ss;
211 auto dst = (unsigned char *)&a;
212 a.ss_len = 0;
213 dst += sizeof(a.ss_len);
214 a.ss_family = ss.ss_family;
215 src += sizeof(ss.ss_family);
216 dst += sizeof(a.ss_family);
217 auto const copy_size = std::min((unsigned char*)(&ss + 1) - src,
218 (unsigned char*)(&a + 1) - dst);
219 ::memcpy(dst, src, copy_size);
220 #else
221 ceph_sockaddr_storage ss{};
222 decode(ss, bl);
223 ::memcpy(&a, &ss, std::min(sizeof(ss), sizeof(a)));
224 #endif
225 }
226
227 /*
228 * an entity's network address.
229 * includes a random value that prevents it from being reused.
230 * thus identifies a particular process instance.
231 * ipv4 for now.
232 */
233 struct entity_addr_t {
234 typedef enum {
235 TYPE_NONE = 0,
236 TYPE_LEGACY = 1, ///< legacy msgr1 protocol (ceph jewel and older)
237 TYPE_MSGR2 = 2, ///< msgr2 protocol (new in ceph kraken)
238 TYPE_ANY = 3, ///< ambiguous
239 } type_t;
240 static const type_t TYPE_DEFAULT = TYPE_MSGR2;
241 static std::string_view get_type_name(int t) {
242 switch (t) {
243 case TYPE_NONE: return "none";
244 case TYPE_LEGACY: return "v1";
245 case TYPE_MSGR2: return "v2";
246 case TYPE_ANY: return "any";
247 default: return "???";
248 }
249 };
250
251 __u32 type;
252 __u32 nonce;
253 union {
254 sockaddr sa;
255 sockaddr_in sin;
256 sockaddr_in6 sin6;
257 } u;
258
259 entity_addr_t() : type(0), nonce(0) {
260 memset(&u, 0, sizeof(u));
261 }
262 entity_addr_t(__u32 _type, __u32 _nonce) : type(_type), nonce(_nonce) {
263 memset(&u, 0, sizeof(u));
264 }
265 explicit entity_addr_t(const ceph_entity_addr &o) {
266 type = o.type;
267 nonce = o.nonce;
268 memcpy(&u, &o.in_addr, sizeof(u));
269 #if !defined(__FreeBSD__)
270 u.sa.sa_family = ntohs(u.sa.sa_family);
271 #endif
272 }
273
274 uint32_t get_type() const { return type; }
275 void set_type(uint32_t t) { type = t; }
276 bool is_legacy() const { return type == TYPE_LEGACY; }
277 bool is_msgr2() const { return type == TYPE_MSGR2; }
278 bool is_any() const { return type == TYPE_ANY; }
279
280 __u32 get_nonce() const { return nonce; }
281 void set_nonce(__u32 n) { nonce = n; }
282
283 int get_family() const {
284 return u.sa.sa_family;
285 }
286 void set_family(int f) {
287 u.sa.sa_family = f;
288 }
289
290 bool is_ipv4() const {
291 return u.sa.sa_family == AF_INET;
292 }
293 bool is_ipv6() const {
294 return u.sa.sa_family == AF_INET6;
295 }
296
297 sockaddr_in &in4_addr() {
298 return u.sin;
299 }
300 const sockaddr_in &in4_addr() const{
301 return u.sin;
302 }
303 sockaddr_in6 &in6_addr(){
304 return u.sin6;
305 }
306 const sockaddr_in6 &in6_addr() const{
307 return u.sin6;
308 }
309 const sockaddr *get_sockaddr() const {
310 return &u.sa;
311 }
312 size_t get_sockaddr_len() const {
313 switch (u.sa.sa_family) {
314 case AF_INET:
315 return sizeof(u.sin);
316 case AF_INET6:
317 return sizeof(u.sin6);
318 }
319 return sizeof(u);
320 }
321 bool set_sockaddr(const struct sockaddr *sa)
322 {
(1) Event switch: |
Switch case value "10". |
323 switch (sa->sa_family) {
324 case AF_INET:
325 // pre-zero, since we're only copying a portion of the source
326 memset(&u, 0, sizeof(u));
327 memcpy(&u.sin, sa, sizeof(u.sin));
328 break;
(2) Event switch_case: |
Reached case "10". |
329 case AF_INET6:
330 // pre-zero, since we're only copying a portion of the source
331 memset(&u, 0, sizeof(u));
(3) Event access_dbuff_const: |
Calling "memcpy" indexes array "sa" with index "28UL" at byte position 27. |
332 memcpy(&u.sin6, sa, sizeof(u.sin6));
333 break;
334 case AF_UNSPEC:
335 memset(&u, 0, sizeof(u));
336 break;
337 default:
338 return false;
339 }
340 return true;
341 }
342
343 sockaddr_storage get_sockaddr_storage() const {
344 sockaddr_storage ss;
345 memcpy(&ss, &u, sizeof(u));
346 memset((char*)&ss + sizeof(u), 0, sizeof(ss) - sizeof(u));
347 return ss;
348 }
349
350 void set_in4_quad(int pos, int val) {
351 u.sin.sin_family = AF_INET;
352 unsigned char *ipq = (unsigned char*)&u.sin.sin_addr.s_addr;
353 ipq[pos] = val;
354 }
355 void set_port(int port) {
356 switch (u.sa.sa_family) {
357 case AF_INET:
358 u.sin.sin_port = htons(port);
359 break;
360 case AF_INET6:
361 u.sin6.sin6_port = htons(port);
362 break;
363 default:
364 ceph_abort();
365 }
366 }
367 int get_port() const {
368 switch (u.sa.sa_family) {
369 case AF_INET:
370 return ntohs(u.sin.sin_port);
371 break;
372 case AF_INET6:
373 return ntohs(u.sin6.sin6_port);
374 break;
375 }
376 return 0;
377 }
378
379 operator ceph_entity_addr() const {
380 ceph_entity_addr a;
381 a.type = 0;
382 a.nonce = nonce;
383 a.in_addr = get_sockaddr_storage();
384 #if !defined(__FreeBSD__)
385 a.in_addr.ss_family = htons(a.in_addr.ss_family);
386 #endif
387 return a;
388 }
389
390 bool probably_equals(const entity_addr_t &o) const {
391 if (get_port() != o.get_port())
392 return false;
393 if (get_nonce() != o.get_nonce())
394 return false;
395 if (is_blank_ip() || o.is_blank_ip())
396 return true;
397 if (memcmp(&u, &o.u, sizeof(u)) == 0)
398 return true;
399 return false;
400 }
401
402 bool is_same_host(const entity_addr_t &o) const {
403 if (u.sa.sa_family != o.u.sa.sa_family)
404 return false;
405 if (u.sa.sa_family == AF_INET)
406 return u.sin.sin_addr.s_addr == o.u.sin.sin_addr.s_addr;
407 if (u.sa.sa_family == AF_INET6)
408 return memcmp(u.sin6.sin6_addr.s6_addr,
409 o.u.sin6.sin6_addr.s6_addr,
410 sizeof(u.sin6.sin6_addr.s6_addr)) == 0;
411 return false;
412 }
413
414 bool is_blank_ip() const {
415 switch (u.sa.sa_family) {
416 case AF_INET:
417 return u.sin.sin_addr.s_addr == INADDR_ANY;
418 case AF_INET6:
419 return memcmp(&u.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0;
420 default:
421 return true;
422 }
423 }
424
425 bool is_ip() const {
426 switch (u.sa.sa_family) {
427 case AF_INET:
428 case AF_INET6:
429 return true;
430 default:
431 return false;
432 }
433 }
434
435 std::string ip_only_to_str() const;
436
437 std::string get_legacy_str() const {
438 std::ostringstream ss;
439 ss << get_sockaddr() << "/" << get_nonce();
440 return ss.str();
441 }
442
443 bool parse(const char *s, const char **end = 0, int type=0);
444
445 void decode_legacy_addr_after_marker(ceph::buffer::list::const_iterator& bl)
446 {
447 using ceph::decode;
448 __u8 marker;
449 __u16 rest;
450 decode(marker, bl);
451 decode(rest, bl);
452 decode(nonce, bl);
453 sockaddr_storage ss;
454 decode(ss, bl);
455 set_sockaddr((sockaddr*)&ss);
456 if (get_family() == AF_UNSPEC) {
457 type = TYPE_NONE;
458 } else {
459 type = TYPE_LEGACY;
460 }
461 }
462
463 // Right now, these only deal with sockaddr_storage that have only family and content.
464 // Apparently on BSD there is also an ss_len that we need to handle; this requires
465 // broader study
466
467 void encode(ceph::buffer::list& bl, uint64_t features) const {
468 using ceph::encode;
469 if ((features & CEPH_FEATURE_MSG_ADDR2) == 0) {
470 encode((__u32)0, bl);
471 encode(nonce, bl);
472 sockaddr_storage ss = get_sockaddr_storage();
473 encode(ss, bl);
474 return;
475 }
476 encode((__u8)1, bl);
477 ENCODE_START(1, 1, bl);
478 if (HAVE_FEATURE(features, SERVER_NAUTILUS)) {
479 encode(type, bl);
480 } else {
481 // map any -> legacy for old clients. this is primary for the benefit
482 // of OSDMap's blacklist, but is reasonable in general since any: is
483 // meaningless for pre-nautilus clients or daemons.
484 auto t = type;
485 if (t == TYPE_ANY) {
486 t = TYPE_LEGACY;
487 }
488 encode(t, bl);
489 }
490 encode(nonce, bl);
491 __u32 elen = get_sockaddr_len();
492 #if (__FreeBSD__) || defined(__APPLE__)
493 elen -= sizeof(u.sa.sa_len);
494 #endif
495 encode(elen, bl);
496 if (elen) {
497 uint16_t ss_family = u.sa.sa_family;
498
499 encode(ss_family, bl);
500 elen -= sizeof(u.sa.sa_family);
501 bl.append(u.sa.sa_data, elen);
502 }
503 ENCODE_FINISH(bl);
504 }
505 void decode(ceph::buffer::list::const_iterator& bl) {
506 using ceph::decode;
507 __u8 marker;
508 decode(marker, bl);
509 if (marker == 0) {
510 decode_legacy_addr_after_marker(bl);
511 return;
512 }
513 if (marker != 1)
514 throw ceph::buffer::malformed_input("entity_addr_t marker != 1");
515 DECODE_START(1, bl);
516 decode(type, bl);
517 decode(nonce, bl);
518 __u32 elen;
519 decode(elen, bl);
520 if (elen) {
521 #if defined(__FreeBSD__) || defined(__APPLE__)
522 u.sa.sa_len = 0;
523 #endif
524 uint16_t ss_family;
525 if (elen < sizeof(ss_family)) {
526 throw buffer::malformed_input("elen smaller than family len");
527 }
528 decode(ss_family, bl);
529 u.sa.sa_family = ss_family;
530 elen -= sizeof(ss_family);
531 if (elen > get_sockaddr_len() - sizeof(u.sa.sa_family)) {
532 throw buffer::malformed_input("elen exceeds sockaddr len");
533 }
534 bl.copy(elen, u.sa.sa_data);
535 }
536 DECODE_FINISH(bl);
537 }
538
539 void dump(ceph::Formatter *f) const;
540
541 static void generate_test_instances(std::list<entity_addr_t*>& o);
542 };
543 WRITE_CLASS_ENCODER_FEATURES(entity_addr_t)
544
545 std::ostream& operator<<(std::ostream& out, const entity_addr_t &addr);
546
547 inline bool operator==(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) == 0; }
548 inline bool operator!=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) != 0; }
549 inline bool operator<(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) < 0; }
550 inline bool operator<=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) <= 0; }
551 inline bool operator>(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) > 0; }
552 inline bool operator>=(const entity_addr_t& a, const entity_addr_t& b) { return memcmp(&a, &b, sizeof(a)) >= 0; }
553
554 namespace std {
555 template<> struct hash<entity_addr_t> {
556 size_t operator()( const entity_addr_t& x ) const {
557 static blobhash H;
558 return H(&x, sizeof(x));
559 }
560 };
561 } // namespace std
562
563 struct entity_addrvec_t {
564 std::vector<entity_addr_t> v;
565
566 entity_addrvec_t() {}
567 explicit entity_addrvec_t(const entity_addr_t& a) : v({ a }) {}
568
569 unsigned size() const { return v.size(); }
570 bool empty() const { return v.empty(); }
571
572 entity_addr_t legacy_addr() const {
573 for (auto& a : v) {
574 if (a.type == entity_addr_t::TYPE_LEGACY) {
575 return a;
576 }
577 }
578 return entity_addr_t();
579 }
580 entity_addr_t as_legacy_addr() const {
581 for (auto& a : v) {
582 if (a.is_legacy()) {
583 return a;
584 }
585 if (a.is_any()) {
586 auto b = a;
587 b.set_type(entity_addr_t::TYPE_LEGACY);
588 return b;
589 }
590 }
591 // hrm... lie!
592 auto a = front();
593 a.set_type(entity_addr_t::TYPE_LEGACY);
594 return a;
595 }
596 entity_addr_t front() const {
597 if (!v.empty()) {
598 return v.front();
599 }
600 return entity_addr_t();
601 }
602 entity_addr_t legacy_or_front_addr() const {
603 for (auto& a : v) {
604 if (a.type == entity_addr_t::TYPE_LEGACY) {
605 return a;
606 }
607 }
608 if (!v.empty()) {
609 return v.front();
610 }
611 return entity_addr_t();
612 }
613 std::string get_legacy_str() const {
614 return legacy_or_front_addr().get_legacy_str();
615 }
616
617 entity_addr_t msgr2_addr() const {
618 for (auto &a : v) {
619 if (a.type == entity_addr_t::TYPE_MSGR2) {
620 return a;
621 }
622 }
623 return entity_addr_t();
624 }
625 bool has_msgr2() const {
626 for (auto& a : v) {
627 if (a.is_msgr2()) {
628 return true;
629 }
630 }
631 return false;
632 }
633
634 bool parse(const char *s, const char **end = 0);
635
636 void get_ports(std::set<int> *ports) const {
637 for (auto& a : v) {
638 ports->insert(a.get_port());
639 }
640 }
641 std::set<int> get_ports() const {
642 std::set<int> r;
643 get_ports(&r);
644 return r;
645 }
646
647 void encode(ceph::buffer::list& bl, uint64_t features) const;
648 void decode(ceph::buffer::list::const_iterator& bl);
649 void dump(ceph::Formatter *f) const;
650 static void generate_test_instances(std::list<entity_addrvec_t*>& ls);
651
652 bool legacy_equals(const entity_addrvec_t& o) const {
653 if (v == o.v) {
654 return true;
655 }
656 if (v.size() == 1 &&
657 front().is_legacy() &&
658 front() == o.legacy_addr()) {
659 return true;
660 }
661 if (o.v.size() == 1 &&
662 o.front().is_legacy() &&
663 o.front() == legacy_addr()) {
664 return true;
665 }
666 return false;
667 }
668
669 bool probably_equals(const entity_addrvec_t& o) const {
670 for (unsigned i = 0; i < v.size(); ++i) {
671 if (!v[i].probably_equals(o.v[i])) {
672 return false;
673 }
674 }
675 return true;
676 }
677 bool contains(const entity_addr_t& a) const {
678 for (auto& i : v) {
679 if (a == i) {
680 return true;
681 }
682 }
683 return false;
684 }
685 bool is_same_host(const entity_addr_t& a) const {
686 for (auto& i : v) {
687 if (i.is_same_host(a)) {
688 return true;
689 }
690 }
691 return false;
692 }
693
694 friend std::ostream& operator<<(std::ostream& out, const entity_addrvec_t& av) {
695 if (av.v.empty()) {
696 return out;
697 } else if (av.v.size() == 1) {
698 return out << av.v[0];
699 } else {
700 return out << av.v;
701 }
702 }
703
704 friend bool operator==(const entity_addrvec_t& l, const entity_addrvec_t& r) {
705 return l.v == r.v;
706 }
707 friend bool operator!=(const entity_addrvec_t& l, const entity_addrvec_t& r) {
708 return l.v != r.v;
709 }
710 friend bool operator<(const entity_addrvec_t& l, const entity_addrvec_t& r) {
711 return l.v < r.v; // see lexicographical_compare()
712 }
713 };
714 WRITE_CLASS_ENCODER_FEATURES(entity_addrvec_t);
715
716 namespace std {
717 template<> struct hash<entity_addrvec_t> {
718 size_t operator()( const entity_addrvec_t& x) const {
719 static blobhash H;
720 size_t r = 0;
721 for (auto& i : x.v) {
722 r += H((const char*)&i, sizeof(i));
723 }
724 return r;
725 }
726 };
727 } // namespace std
728
729 /*
730 * a particular entity instance
731 */
732 struct entity_inst_t {
733 entity_name_t name;
734 entity_addr_t addr;
735 entity_inst_t() {}
736 entity_inst_t(entity_name_t n, const entity_addr_t& a) : name(n), addr(a) {}
737 // cppcheck-suppress noExplicitConstructor
738 entity_inst_t(const ceph_entity_inst& i) : name(i.name), addr(i.addr) { }
739 entity_inst_t(const ceph_entity_name& n, const ceph_entity_addr &a) : name(n), addr(a) {}
740 operator ceph_entity_inst() {
741 ceph_entity_inst i = {name, addr};
742 return i;
743 }
744
745 void encode(ceph::buffer::list& bl, uint64_t features) const {
746 using ceph::encode;
747 encode(name, bl);
748 encode(addr, bl, features);
749 }
750 void decode(ceph::buffer::list::const_iterator& bl) {
751 using ceph::decode;
752 decode(name, bl);
753 decode(addr, bl);
754 }
755
756 void dump(ceph::Formatter *f) const;
757 static void generate_test_instances(std::list<entity_inst_t*>& o);
758 };
759 WRITE_CLASS_ENCODER_FEATURES(entity_inst_t)
760
761
762 inline bool operator==(const entity_inst_t& a, const entity_inst_t& b) {
763 return a.name == b.name && a.addr == b.addr;
764 }
765 inline bool operator!=(const entity_inst_t& a, const entity_inst_t& b) {
766 return a.name != b.name || a.addr != b.addr;
767 }
768 inline bool operator<(const entity_inst_t& a, const entity_inst_t& b) {
769 return a.name < b.name || (a.name == b.name && a.addr < b.addr);
770 }
771 inline bool operator<=(const entity_inst_t& a, const entity_inst_t& b) {
772 return a.name < b.name || (a.name == b.name && a.addr <= b.addr);
773 }
774 inline bool operator>(const entity_inst_t& a, const entity_inst_t& b) { return b < a; }
775 inline bool operator>=(const entity_inst_t& a, const entity_inst_t& b) { return b <= a; }
776
777 namespace std {
778 template<> struct hash< entity_inst_t >
779 {
780 size_t operator()( const entity_inst_t& x ) const
781 {
782 static hash< entity_name_t > H;
783 static hash< entity_addr_t > I;
784 return H(x.name) ^ I(x.addr);
785 }
786 };
787 } // namespace std
788
789
790 inline std::ostream& operator<<(std::ostream& out, const entity_inst_t &i)
791 {
792 return out << i.name << " " << i.addr;
793 }
794 inline std::ostream& operator<<(std::ostream& out, const ceph_entity_inst &i)
795 {
796 entity_inst_t n = i;
797 return out << n;
798 }
799
800 #endif
801