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.
19 #include "include/scope_guard.h"
20 #include "include/stringify.h"
22 #include "messages/MMonGetMap.h"
23 #include "messages/MMonGetVersion.h"
24 #include "messages/MMonGetVersionReply.h"
25 #include "messages/MMonMap.h"
26 #include "messages/MConfig.h"
27 #include "messages/MGetConfig.h"
28 #include "messages/MAuth.h"
29 #include "messages/MLogAck.h"
30 #include "messages/MAuthReply.h"
31 #include "messages/MMonCommand.h"
32 #include "messages/MMonCommandAck.h"
33 #include "messages/MPing.h"
35 #include "messages/MMonSubscribe.h"
36 #include "messages/MMonSubscribeAck.h"
37 #include "common/errno.h"
38 #include "common/hostname.h"
39 #include "common/LogClient.h"
41 #include "MonClient.h"
44 #include "auth/Auth.h"
45 #include "auth/KeyRing.h"
46 #include "auth/AuthClientHandler.h"
47 #include "auth/AuthMethodList.h"
48 #include "auth/AuthRegistry.h"
49 #include "auth/RotatingKeyRing.h"
51 #define dout_subsys ceph_subsys_monc
53 #define dout_prefix *_dout << "monclient" << (_hunting() ? "(hunting)":"") << ": "
55 MonClient::MonClient(CephContext
*cct_
) :
59 monc_lock("MonClient::monc_lock"),
60 timer(cct_
, monc_lock
),
64 more_log_pending(false),
66 had_a_connection(false),
67 reopen_interval_multiplier(
68 cct_
->_conf
.get_val
<double>("mon_client_hunt_interval_min_multiple")),
69 last_mon_command_tid(0),
73 MonClient::~MonClient()
77 int MonClient::build_initial_monmap()
79 ldout(cct
, 10) << __func__
<< dendl
;
80 int r
= monmap
.build_initial(cct
, false, cerr
);
81 ldout(cct
,10) << "monmap:\n";
87 int MonClient::get_monmap()
89 ldout(cct
, 10) << __func__
<< dendl
;
90 std::lock_guard
l(monc_lock
);
92 sub
.want("monmap", 0, 0);
97 map_cond
.Wait(monc_lock
);
99 ldout(cct
, 10) << __func__
<< " done" << dendl
;
103 int MonClient::get_monmap_and_config()
105 ldout(cct
, 10) << __func__
<< dendl
;
106 ceph_assert(!messenger
);
111 interval
.set_from_double(cct
->_conf
->mon_client_hunt_interval
);
114 auto shutdown_crypto
= make_scope_guard([this] {
115 cct
->shutdown_crypto();
118 int r
= build_initial_monmap();
120 lderr(cct
) << __func__
<< " cannot identify monitors to contact" << dendl
;
124 messenger
= Messenger::create_client_messenger(
125 cct
, "temp_mon_client");
126 ceph_assert(messenger
);
127 messenger
->add_dispatcher_head(this);
129 auto shutdown_msgr
= make_scope_guard([this] {
130 messenger
->shutdown();
134 if (!monmap
.fsid
.is_zero()) {
135 cct
->_conf
.set_val("fsid", stringify(monmap
.fsid
));
139 while (tries
-- > 0) {
144 r
= authenticate(cct
->_conf
->client_mount_timeout
);
145 if (r
== -ETIMEDOUT
) {
153 std::lock_guard
l(monc_lock
);
154 if (monmap
.get_epoch() &&
155 !monmap
.persistent_features
.contains_all(
156 ceph::features::mon::FEATURE_MIMIC
)) {
157 ldout(cct
,10) << __func__
<< " pre-mimic monitor, no config to fetch"
162 while ((!got_config
|| monmap
.get_epoch() == 0) && r
== 0) {
163 ldout(cct
,20) << __func__
<< " waiting for monmap|config" << dendl
;
164 r
= map_cond
.WaitInterval(monc_lock
, interval
);
167 ldout(cct
,10) << __func__
<< " success" << dendl
;
172 lderr(cct
) << __func__
<< " failed to get config" << dendl
;
183 * Ping the monitor with id @p mon_id and set the resulting reply in
184 * the provided @p result_reply, if this last parameter is not NULL.
186 * So that we don't rely on the MonClient's default messenger, set up
187 * during connect(), we create our own messenger to comunicate with the
188 * specified monitor. This is advantageous in the following ways:
190 * - Isolate the ping procedure from the rest of the MonClient's operations,
191 * allowing us to not acquire or manage the big monc_lock, thus not
192 * having to block waiting for some other operation to finish before we
194 * * for instance, we can ping mon.FOO even if we are currently hunting
195 * or blocked waiting for auth to complete with mon.BAR.
197 * - Ping a monitor prior to establishing a connection (using connect())
198 * and properly establish the MonClient's messenger. This frees us
199 * from dealing with the complex foo that happens in connect().
201 * We also don't rely on MonClient as a dispatcher for this messenger,
202 * unlike what happens with the MonClient's default messenger. This allows
203 * us to sandbox the whole ping, having it much as a separate entity in
204 * the MonClient class, considerably simplifying the handling and dispatching
205 * of messages without needing to consider monc_lock.
207 * Current drawback is that we will establish a messenger for each ping
208 * we want to issue, instead of keeping a single messenger instance that
209 * would be used for all pings.
211 int MonClient::ping_monitor(const string
&mon_id
, string
*result_reply
)
213 ldout(cct
, 10) << __func__
<< dendl
;
216 if (monmap
.contains("noname-"+mon_id
)) {
217 new_mon_id
= "noname-"+mon_id
;
222 if (new_mon_id
.empty()) {
223 ldout(cct
, 10) << __func__
<< " specified mon id is empty!" << dendl
;
225 } else if (!monmap
.contains(new_mon_id
)) {
226 ldout(cct
, 10) << __func__
<< " no such monitor 'mon." << new_mon_id
<< "'"
231 // N.B. monc isn't initialized
233 auth_registry
.refresh_config();
236 keyring
.from_ceph_context(cct
);
237 RotatingKeyRing
rkeyring(cct
, cct
->get_module_type(), &keyring
);
239 MonClientPinger
*pinger
= new MonClientPinger(cct
,
243 Messenger
*smsgr
= Messenger::create_client_messenger(cct
, "temp_ping_client");
244 smsgr
->add_dispatcher_head(pinger
);
245 smsgr
->set_auth_client(pinger
);
248 ConnectionRef con
= smsgr
->connect_to_mon(monmap
.get_addrs(new_mon_id
));
249 ldout(cct
, 10) << __func__
<< " ping mon." << new_mon_id
250 << " " << con
->get_peer_addr() << dendl
;
252 pinger
->mc
.reset(new MonConnection(cct
, con
, 0, &auth_registry
));
253 pinger
->mc
->start(monmap
.get_epoch(), entity_name
);
254 con
->send_message(new MPing
);
257 int ret
= pinger
->wait_for_reply(cct
->_conf
->mon_client_ping_timeout
);
259 ldout(cct
,10) << __func__
<< " got ping reply" << dendl
;
263 pinger
->lock
.Unlock();
274 bool MonClient::ms_dispatch(Message
*m
)
276 // we only care about these message types
277 switch (m
->get_type()) {
278 case CEPH_MSG_MON_MAP
:
279 case CEPH_MSG_AUTH_REPLY
:
280 case CEPH_MSG_MON_SUBSCRIBE_ACK
:
281 case CEPH_MSG_MON_GET_VERSION_REPLY
:
282 case MSG_MON_COMMAND_ACK
:
293 std::lock_guard
lock(monc_lock
);
296 auto p
= _find_pending_con(m
->get_connection());
297 if (p
== pending_cons
.end()) {
298 // ignore any messages outside hunting sessions
299 ldout(cct
, 10) << "discarding stray monitor message " << *m
<< dendl
;
303 } else if (!active_con
|| active_con
->get_con() != m
->get_connection()) {
304 // ignore any messages outside our session(s)
305 ldout(cct
, 10) << "discarding stray monitor message " << *m
<< dendl
;
310 switch (m
->get_type()) {
311 case CEPH_MSG_MON_MAP
:
312 handle_monmap(static_cast<MMonMap
*>(m
));
313 if (passthrough_monmap
) {
319 case CEPH_MSG_AUTH_REPLY
:
320 handle_auth(static_cast<MAuthReply
*>(m
));
322 case CEPH_MSG_MON_SUBSCRIBE_ACK
:
323 handle_subscribe_ack(static_cast<MMonSubscribeAck
*>(m
));
325 case CEPH_MSG_MON_GET_VERSION_REPLY
:
326 handle_get_version_reply(static_cast<MMonGetVersionReply
*>(m
));
328 case MSG_MON_COMMAND_ACK
:
329 handle_mon_command_ack(static_cast<MMonCommandAck
*>(m
));
333 log_client
->handle_log_ack(static_cast<MLogAck
*>(m
));
335 if (more_log_pending
) {
343 handle_config(static_cast<MConfig
*>(m
));
349 void MonClient::send_log(bool flush
)
352 Message
*lm
= log_client
->get_mon_log_message(flush
);
354 _send_mon_message(lm
);
355 more_log_pending
= log_client
->are_pending();
359 void MonClient::flush_log()
361 std::lock_guard
l(monc_lock
);
365 /* Unlike all the other message-handling functions, we don't put away a reference
366 * because we want to support MMonMap passthrough to other Dispatchers. */
367 void MonClient::handle_monmap(MMonMap
*m
)
369 ldout(cct
, 10) << __func__
<< " " << *m
<< dendl
;
370 auto con_addrs
= m
->get_source_addrs();
371 string old_name
= monmap
.get_name(con_addrs
);
373 // NOTE: we're not paying attention to the epoch, here.
374 auto p
= m
->monmapbl
.cbegin();
377 ldout(cct
, 10) << " got monmap " << monmap
.epoch
378 << " from mon." << old_name
379 << " (according to old e" << monmap
.get_epoch() << ")"
381 ldout(cct
, 10) << "dump:\n";
382 monmap
.print(*_dout
);
385 if (old_name
.size() == 0) {
386 ldout(cct
,10) << " can't identify which mon we were connected to" << dendl
;
389 int new_rank
= monmap
.get_rank(m
->get_source_addr());
391 ldout(cct
, 10) << "mon." << new_rank
<< " at " << m
->get_source_addrs()
392 << " went away" << dendl
;
393 // can't find the mon we were talking to (above)
395 } else if (messenger
->should_use_msgr2() &&
396 monmap
.get_addrs(new_rank
).has_msgr2() &&
397 !con_addrs
.has_msgr2()) {
398 ldout(cct
,1) << " mon." << new_rank
<< " has (v2) addrs "
399 << monmap
.get_addrs(new_rank
) << " but i'm connected to "
400 << con_addrs
<< ", reconnecting" << dendl
;
405 sub
.got("monmap", monmap
.get_epoch());
409 if (authenticate_err
== 1) {
414 void MonClient::handle_config(MConfig
*m
)
416 ldout(cct
,10) << __func__
<< " " << *m
<< dendl
;
417 finisher
.queue(new FunctionContext([this, m
](int r
) {
418 cct
->_conf
.set_mon_vals(cct
, m
->config
, config_cb
);
419 if (config_notify_cb
) {
428 // ----------------------
430 int MonClient::init()
432 ldout(cct
, 10) << __func__
<< dendl
;
434 entity_name
= cct
->_conf
->name
;
436 auth_registry
.refresh_config();
438 std::lock_guard
l(monc_lock
);
439 keyring
.reset(new KeyRing
);
440 if (auth_registry
.is_supported_method(messenger
->get_mytype(),
442 // this should succeed, because auth_registry just checked!
443 int r
= keyring
->from_ceph_context(cct
);
445 // but be somewhat graceful in case there was a race condition
446 lderr(cct
) << "keyring not found" << dendl
;
450 if (!auth_registry
.any_supported_methods(messenger
->get_mytype())) {
454 rotating_secrets
.reset(
455 new RotatingKeyRing(cct
, cct
->get_module_type(), keyring
.get()));
459 messenger
->set_auth_client(this);
460 messenger
->add_dispatcher_head(this);
469 void MonClient::shutdown()
471 ldout(cct
, 10) << __func__
<< dendl
;
474 while (!version_requests
.empty()) {
475 version_requests
.begin()->second
->context
->complete(-ECANCELED
);
476 ldout(cct
, 20) << __func__
<< " canceling and discarding version request "
477 << version_requests
.begin()->second
<< dendl
;
478 delete version_requests
.begin()->second
;
479 version_requests
.erase(version_requests
.begin());
481 while (!mon_commands
.empty()) {
482 auto tid
= mon_commands
.begin()->first
;
483 _cancel_mon_command(tid
);
485 while (!waiting_for_session
.empty()) {
486 ldout(cct
, 20) << __func__
<< " discarding pending message " << *waiting_for_session
.front() << dendl
;
487 waiting_for_session
.front()->put();
488 waiting_for_session
.pop_front();
492 pending_cons
.clear();
498 finisher
.wait_for_empty();
508 int MonClient::authenticate(double timeout
)
510 std::lock_guard
lock(monc_lock
);
513 ldout(cct
, 5) << "already authenticated" << dendl
;
516 sub
.want("monmap", monmap
.get_epoch() ? monmap
.get_epoch() + 1 : 0, 0);
517 sub
.want("config", 0, 0);
521 utime_t until
= ceph_clock_now();
524 ldout(cct
, 10) << "authenticate will time out at " << until
<< dendl
;
525 authenticate_err
= 1; // == in progress
526 while (!active_con
&& authenticate_err
>= 0) {
528 int r
= auth_cond
.WaitUntil(monc_lock
, until
);
529 if (r
== ETIMEDOUT
&& !active_con
) {
530 ldout(cct
, 0) << "authenticate timed out after " << timeout
<< dendl
;
531 authenticate_err
= -r
;
534 auth_cond
.Wait(monc_lock
);
539 ldout(cct
, 5) << __func__
<< " success, global_id "
540 << active_con
->get_global_id() << dendl
;
541 // active_con should not have been set if there was an error
542 ceph_assert(authenticate_err
>= 0);
543 authenticated
= true;
546 if (authenticate_err
< 0 && auth_registry
.no_keyring_disabled_cephx()) {
547 lderr(cct
) << __func__
<< " NOTE: no keyring found; disabled cephx authentication" << dendl
;
550 return authenticate_err
;
553 void MonClient::handle_auth(MAuthReply
*m
)
555 ceph_assert(monc_lock
.is_locked());
557 std::swap(active_con
->get_auth(), auth
);
558 int ret
= active_con
->authenticate(m
);
560 std::swap(auth
, active_con
->get_auth());
561 if (global_id
!= active_con
->get_global_id()) {
562 lderr(cct
) << __func__
<< " peer assigned me a different global_id: "
563 << active_con
->get_global_id() << dendl
;
565 if (ret
!= -EAGAIN
) {
572 auto found
= _find_pending_con(m
->get_connection());
573 ceph_assert(found
!= pending_cons
.end());
574 int auth_err
= found
->second
.handle_auth(m
, entity_name
, want_keys
,
575 rotating_secrets
.get());
577 if (auth_err
== -EAGAIN
) {
581 pending_cons
.erase(found
);
582 if (!pending_cons
.empty()) {
583 // keep trying with pending connections
586 // the last try just failed, give up.
588 auto& mc
= found
->second
;
589 ceph_assert(mc
.have_session());
590 active_con
.reset(new MonConnection(std::move(mc
)));
591 pending_cons
.clear();
594 _finish_hunting(auth_err
);
595 _finish_auth(auth_err
);
598 void MonClient::_finish_auth(int auth_err
)
600 ldout(cct
,10) << __func__
<< " " << auth_err
<< dendl
;
601 authenticate_err
= auth_err
;
602 // _resend_mon_commands() could _reopen_session() if the connected mon is not
603 // the one the MonCommand is targeting.
604 if (!auth_err
&& active_con
) {
606 _check_auth_tickets();
608 auth_cond
.SignalAll();
611 Context
*cb
= nullptr;
612 if (session_established_context
) {
613 cb
= session_established_context
.release();
625 void MonClient::_send_mon_message(Message
*m
)
627 ceph_assert(monc_lock
.is_locked());
629 auto cur_con
= active_con
->get_con();
630 ldout(cct
, 10) << "_send_mon_message to mon."
631 << monmap
.get_name(cur_con
->get_peer_addr())
632 << " at " << cur_con
->get_peer_addr() << dendl
;
633 cur_con
->send_message(m
);
635 waiting_for_session
.push_back(m
);
639 void MonClient::_reopen_session(int rank
)
641 ceph_assert(monc_lock
.is_locked());
642 ldout(cct
, 10) << __func__
<< " rank " << rank
<< dendl
;
645 pending_cons
.clear();
650 _add_conn(rank
, global_id
);
652 _add_conns(global_id
);
655 // throw out old queued messages
656 while (!waiting_for_session
.empty()) {
657 waiting_for_session
.front()->put();
658 waiting_for_session
.pop_front();
661 // throw out version check requests
662 while (!version_requests
.empty()) {
663 finisher
.queue(version_requests
.begin()->second
->context
, -EAGAIN
);
664 delete version_requests
.begin()->second
;
665 version_requests
.erase(version_requests
.begin());
668 for (auto& c
: pending_cons
) {
669 c
.second
.start(monmap
.get_epoch(), entity_name
);
677 MonConnection
& MonClient::_add_conn(unsigned rank
, uint64_t global_id
)
679 auto peer
= monmap
.get_addrs(rank
);
680 auto conn
= messenger
->connect_to_mon(peer
);
681 MonConnection
mc(cct
, conn
, global_id
, &auth_registry
);
682 auto inserted
= pending_cons
.insert(make_pair(peer
, move(mc
)));
683 ldout(cct
, 10) << "picked mon." << monmap
.get_name(rank
)
687 return inserted
.first
->second
;
690 void MonClient::_add_conns(uint64_t global_id
)
692 uint16_t min_priority
= std::numeric_limits
<uint16_t>::max();
693 for (const auto& m
: monmap
.mon_info
) {
694 if (m
.second
.priority
< min_priority
) {
695 min_priority
= m
.second
.priority
;
698 vector
<unsigned> ranks
;
699 for (const auto& m
: monmap
.mon_info
) {
700 if (m
.second
.priority
== min_priority
) {
701 ranks
.push_back(monmap
.get_rank(m
.first
));
704 std::random_device rd
;
705 std::mt19937
rng(rd());
706 std::shuffle(ranks
.begin(), ranks
.end(), rng
);
707 unsigned n
= cct
->_conf
->mon_client_hunt_parallel
;
708 if (n
== 0 || n
> ranks
.size()) {
711 for (unsigned i
= 0; i
< n
; i
++) {
712 _add_conn(ranks
[i
], global_id
);
716 bool MonClient::ms_handle_reset(Connection
*con
)
718 std::lock_guard
lock(monc_lock
);
720 if (con
->get_peer_type() != CEPH_ENTITY_TYPE_MON
)
724 if (pending_cons
.count(con
->get_peer_addrs())) {
725 ldout(cct
, 10) << __func__
<< " hunted mon " << con
->get_peer_addrs()
728 ldout(cct
, 10) << __func__
<< " stray mon " << con
->get_peer_addrs()
733 if (active_con
&& con
== active_con
->get_con()) {
734 ldout(cct
, 10) << __func__
<< " current mon " << con
->get_peer_addrs()
739 ldout(cct
, 10) << "ms_handle_reset stray mon " << con
->get_peer_addrs()
746 bool MonClient::_opened() const
748 ceph_assert(monc_lock
.is_locked());
749 return active_con
|| _hunting();
752 bool MonClient::_hunting() const
754 return !pending_cons
.empty();
757 void MonClient::_start_hunting()
759 ceph_assert(!_hunting());
760 // adjust timeouts if necessary
761 if (!had_a_connection
)
763 reopen_interval_multiplier
*= cct
->_conf
->mon_client_hunt_interval_backoff
;
764 if (reopen_interval_multiplier
>
765 cct
->_conf
->mon_client_hunt_interval_max_multiple
) {
766 reopen_interval_multiplier
=
767 cct
->_conf
->mon_client_hunt_interval_max_multiple
;
771 void MonClient::_finish_hunting(int auth_err
)
773 ldout(cct
,10) << __func__
<< " " << auth_err
<< dendl
;
774 ceph_assert(monc_lock
.is_locked());
775 // the pending conns have been cleaned.
776 ceph_assert(!_hunting());
778 auto con
= active_con
->get_con();
779 ldout(cct
, 1) << "found mon."
780 << monmap
.get_name(con
->get_peer_addr())
783 ldout(cct
, 1) << "no mon sessions established" << dendl
;
786 had_a_connection
= true;
790 last_rotating_renew_sent
= utime_t();
791 while (!waiting_for_session
.empty()) {
792 _send_mon_message(waiting_for_session
.front());
793 waiting_for_session
.pop_front();
795 _resend_mon_commands();
798 std::swap(auth
, active_con
->get_auth());
799 if (global_id
&& global_id
!= active_con
->get_global_id()) {
800 lderr(cct
) << __func__
<< " global_id changed from " << global_id
801 << " to " << active_con
->get_global_id() << dendl
;
803 global_id
= active_con
->get_global_id();
808 void MonClient::tick()
810 ldout(cct
, 10) << __func__
<< dendl
;
812 auto reschedule_tick
= make_scope_guard([this] {
816 _check_auth_tickets();
819 ldout(cct
, 1) << "continuing hunt" << dendl
;
820 return _reopen_session();
821 } else if (active_con
) {
822 // just renew as needed
823 utime_t now
= ceph_clock_now();
824 auto cur_con
= active_con
->get_con();
825 if (!cur_con
->has_feature(CEPH_FEATURE_MON_STATEFUL_SUB
)) {
826 const bool maybe_renew
= sub
.need_renew();
827 ldout(cct
, 10) << "renew subs? -- " << (maybe_renew
? "yes" : "no")
834 cur_con
->send_keepalive();
836 if (cct
->_conf
->mon_client_ping_timeout
> 0 &&
837 cur_con
->has_feature(CEPH_FEATURE_MSGR_KEEPALIVE2
)) {
838 utime_t lk
= cur_con
->get_last_keepalive_ack();
839 utime_t interval
= now
- lk
;
840 if (interval
> cct
->_conf
->mon_client_ping_timeout
) {
841 ldout(cct
, 1) << "no keepalive since " << lk
<< " (" << interval
842 << " seconds), reconnecting" << dendl
;
843 return _reopen_session();
852 void MonClient::_un_backoff()
854 // un-backoff our reconnect interval
855 reopen_interval_multiplier
= std::max(
856 cct
->_conf
.get_val
<double>("mon_client_hunt_interval_min_multiple"),
857 reopen_interval_multiplier
/
858 cct
->_conf
.get_val
<double>("mon_client_hunt_interval_backoff"));
859 ldout(cct
, 20) << __func__
<< " reopen_interval_multipler now "
860 << reopen_interval_multiplier
<< dendl
;
863 void MonClient::schedule_tick()
865 auto do_tick
= make_lambda_context([this]() { tick(); });
867 const auto hunt_interval
= (cct
->_conf
->mon_client_hunt_interval
*
868 reopen_interval_multiplier
);
869 timer
.add_event_after(hunt_interval
, do_tick
);
871 timer
.add_event_after(cct
->_conf
->mon_client_ping_interval
, do_tick
);
877 void MonClient::_renew_subs()
879 ceph_assert(monc_lock
.is_locked());
880 if (!sub
.have_new()) {
881 ldout(cct
, 10) << __func__
<< " - empty" << dendl
;
885 ldout(cct
, 10) << __func__
<< dendl
;
889 MMonSubscribe
*m
= new MMonSubscribe
;
890 m
->what
= sub
.get_subs();
891 m
->hostname
= ceph_get_short_hostname();
892 _send_mon_message(m
);
897 void MonClient::handle_subscribe_ack(MMonSubscribeAck
*m
)
899 sub
.acked(m
->interval
);
903 int MonClient::_check_auth_tickets()
905 ceph_assert(monc_lock
.is_locked());
906 if (active_con
&& auth
) {
907 if (auth
->need_tickets()) {
908 ldout(cct
, 10) << __func__
<< " getting new tickets!" << dendl
;
909 MAuth
*m
= new MAuth
;
910 m
->protocol
= auth
->get_protocol();
911 auth
->prepare_build_request();
912 auth
->build_request(m
->auth_payload
);
913 _send_mon_message(m
);
916 _check_auth_rotating();
921 int MonClient::_check_auth_rotating()
923 ceph_assert(monc_lock
.is_locked());
924 if (!rotating_secrets
||
925 !auth_principal_needs_rotating_keys(entity_name
)) {
926 ldout(cct
, 20) << "_check_auth_rotating not needed by " << entity_name
<< dendl
;
930 if (!active_con
|| !auth
) {
931 ldout(cct
, 10) << "_check_auth_rotating waiting for auth session" << dendl
;
935 utime_t now
= ceph_clock_now();
936 utime_t cutoff
= now
;
937 cutoff
-= std::min(30.0, cct
->_conf
->auth_service_ticket_ttl
/ 4.0);
938 utime_t issued_at_lower_bound
= now
;
939 issued_at_lower_bound
-= cct
->_conf
->auth_service_ticket_ttl
;
940 if (!rotating_secrets
->need_new_secrets(cutoff
)) {
941 ldout(cct
, 10) << "_check_auth_rotating have uptodate secrets (they expire after " << cutoff
<< ")" << dendl
;
942 rotating_secrets
->dump_rotating();
946 ldout(cct
, 10) << "_check_auth_rotating renewing rotating keys (they expired before " << cutoff
<< ")" << dendl
;
947 if (!rotating_secrets
->need_new_secrets() &&
948 rotating_secrets
->need_new_secrets(issued_at_lower_bound
)) {
949 // the key has expired before it has been issued?
950 lderr(cct
) << __func__
<< " possible clock skew, rotating keys expired way too early"
951 << " (before " << issued_at_lower_bound
<< ")" << dendl
;
953 if ((now
> last_rotating_renew_sent
) &&
954 double(now
- last_rotating_renew_sent
) < 1) {
955 ldout(cct
, 10) << __func__
<< " called too often (last: "
956 << last_rotating_renew_sent
<< "), skipping refresh" << dendl
;
959 MAuth
*m
= new MAuth
;
960 m
->protocol
= auth
->get_protocol();
961 if (auth
->build_rotating_request(m
->auth_payload
)) {
962 last_rotating_renew_sent
= now
;
963 _send_mon_message(m
);
970 int MonClient::wait_auth_rotating(double timeout
)
972 std::lock_guard
l(monc_lock
);
973 utime_t now
= ceph_clock_now();
977 // Must be initialized
978 ceph_assert(auth
!= nullptr);
980 if (auth
->get_protocol() == CEPH_AUTH_NONE
)
983 if (!rotating_secrets
)
986 while (auth_principal_needs_rotating_keys(entity_name
) &&
987 rotating_secrets
->need_new_secrets(now
)) {
989 ldout(cct
, 0) << __func__
<< " timed out after " << timeout
<< dendl
;
992 ldout(cct
, 10) << __func__
<< " waiting (until " << until
<< ")" << dendl
;
993 auth_cond
.WaitUntil(monc_lock
, until
);
994 now
= ceph_clock_now();
996 ldout(cct
, 10) << __func__
<< " done" << dendl
;
1002 void MonClient::_send_command(MonCommand
*r
)
1008 peer
= active_con
->get_con()->get_peer_addr();
1011 if (r
->target_rank
>= 0 &&
1012 r
->target_rank
!= monmap
.get_rank(peer
)) {
1013 if (r
->send_attempts
> cct
->_conf
->mon_client_directed_command_retry
) {
1014 _finish_command(r
, -ENXIO
, "mon unavailable");
1017 ldout(cct
, 10) << __func__
<< " " << r
->tid
<< " " << r
->cmd
1018 << " wants rank " << r
->target_rank
1019 << ", reopening session"
1021 if (r
->target_rank
>= (int)monmap
.size()) {
1022 ldout(cct
, 10) << " target " << r
->target_rank
<< " >= max mon " << monmap
.size() << dendl
;
1023 _finish_command(r
, -ENOENT
, "mon rank dne");
1026 _reopen_session(r
->target_rank
);
1030 if (r
->target_name
.length() &&
1031 r
->target_name
!= monmap
.get_name(peer
)) {
1032 if (r
->send_attempts
> cct
->_conf
->mon_client_directed_command_retry
) {
1033 _finish_command(r
, -ENXIO
, "mon unavailable");
1036 ldout(cct
, 10) << __func__
<< " " << r
->tid
<< " " << r
->cmd
1037 << " wants mon " << r
->target_name
1038 << ", reopening session"
1040 if (!monmap
.contains(r
->target_name
)) {
1041 ldout(cct
, 10) << " target " << r
->target_name
<< " not present in monmap" << dendl
;
1042 _finish_command(r
, -ENOENT
, "mon dne");
1045 _reopen_session(monmap
.get_rank(r
->target_name
));
1049 ldout(cct
, 10) << __func__
<< " " << r
->tid
<< " " << r
->cmd
<< dendl
;
1050 MMonCommand
*m
= new MMonCommand(monmap
.fsid
);
1053 m
->set_data(r
->inbl
);
1054 _send_mon_message(m
);
1058 void MonClient::_resend_mon_commands()
1060 // resend any requests
1061 map
<uint64_t,MonCommand
*>::iterator p
= mon_commands
.begin();
1062 while (p
!= mon_commands
.end()) {
1063 auto cmd
= p
->second
;
1065 _send_command(cmd
); // might remove cmd from mon_commands
1069 void MonClient::handle_mon_command_ack(MMonCommandAck
*ack
)
1071 MonCommand
*r
= NULL
;
1072 uint64_t tid
= ack
->get_tid();
1074 if (tid
== 0 && !mon_commands
.empty()) {
1075 r
= mon_commands
.begin()->second
;
1076 ldout(cct
, 10) << __func__
<< " has tid 0, assuming it is " << r
->tid
<< dendl
;
1078 map
<uint64_t,MonCommand
*>::iterator p
= mon_commands
.find(tid
);
1079 if (p
== mon_commands
.end()) {
1080 ldout(cct
, 10) << __func__
<< " " << ack
->get_tid() << " not found" << dendl
;
1087 ldout(cct
, 10) << __func__
<< " " << r
->tid
<< " " << r
->cmd
<< dendl
;
1089 r
->poutbl
->claim(ack
->get_data());
1090 _finish_command(r
, ack
->r
, ack
->rs
);
1094 int MonClient::_cancel_mon_command(uint64_t tid
)
1096 ceph_assert(monc_lock
.is_locked());
1098 map
<ceph_tid_t
, MonCommand
*>::iterator it
= mon_commands
.find(tid
);
1099 if (it
== mon_commands
.end()) {
1100 ldout(cct
, 10) << __func__
<< " tid " << tid
<< " dne" << dendl
;
1104 ldout(cct
, 10) << __func__
<< " tid " << tid
<< dendl
;
1106 MonCommand
*cmd
= it
->second
;
1107 _finish_command(cmd
, -ETIMEDOUT
, "");
1111 void MonClient::_finish_command(MonCommand
*r
, int ret
, string rs
)
1113 ldout(cct
, 10) << __func__
<< " " << r
->tid
<< " = " << ret
<< " " << rs
<< dendl
;
1119 finisher
.queue(r
->onfinish
, ret
);
1120 mon_commands
.erase(r
->tid
);
1124 void MonClient::start_mon_command(const vector
<string
>& cmd
,
1125 const bufferlist
& inbl
,
1126 bufferlist
*outbl
, string
*outs
,
1129 ldout(cct
,10) << __func__
<< " cmd=" << cmd
<< dendl
;
1130 std::lock_guard
l(monc_lock
);
1131 if (!initialized
|| stopping
) {
1133 onfinish
->complete(-ECANCELED
);
1137 MonCommand
*r
= new MonCommand(++last_mon_command_tid
);
1142 r
->onfinish
= onfinish
;
1143 if (cct
->_conf
->rados_mon_op_timeout
> 0) {
1144 class C_CancelMonCommand
: public Context
1149 C_CancelMonCommand(uint64_t tid
, MonClient
*monc
) : tid(tid
), monc(monc
) {}
1150 void finish(int r
) override
{
1151 monc
->_cancel_mon_command(tid
);
1154 r
->ontimeout
= new C_CancelMonCommand(r
->tid
, this);
1155 timer
.add_event_after(cct
->_conf
->rados_mon_op_timeout
, r
->ontimeout
);
1157 mon_commands
[r
->tid
] = r
;
1161 void MonClient::start_mon_command(const string
&mon_name
,
1162 const vector
<string
>& cmd
,
1163 const bufferlist
& inbl
,
1164 bufferlist
*outbl
, string
*outs
,
1167 ldout(cct
,10) << __func__
<< " mon." << mon_name
<< " cmd=" << cmd
<< dendl
;
1168 std::lock_guard
l(monc_lock
);
1169 if (!initialized
|| stopping
) {
1171 onfinish
->complete(-ECANCELED
);
1175 MonCommand
*r
= new MonCommand(++last_mon_command_tid
);
1176 r
->target_name
= mon_name
;
1181 r
->onfinish
= onfinish
;
1182 mon_commands
[r
->tid
] = r
;
1186 void MonClient::start_mon_command(int rank
,
1187 const vector
<string
>& cmd
,
1188 const bufferlist
& inbl
,
1189 bufferlist
*outbl
, string
*outs
,
1192 ldout(cct
,10) << __func__
<< " rank " << rank
<< " cmd=" << cmd
<< dendl
;
1193 std::lock_guard
l(monc_lock
);
1194 if (!initialized
|| stopping
) {
1196 onfinish
->complete(-ECANCELED
);
1200 MonCommand
*r
= new MonCommand(++last_mon_command_tid
);
1201 r
->target_rank
= rank
;
1206 r
->onfinish
= onfinish
;
1207 mon_commands
[r
->tid
] = r
;
1213 void MonClient::get_version(string map
, version_t
*newest
, version_t
*oldest
, Context
*onfinish
)
1215 version_req_d
*req
= new version_req_d(onfinish
, newest
, oldest
);
1216 ldout(cct
, 10) << "get_version " << map
<< " req " << req
<< dendl
;
1217 std::lock_guard
l(monc_lock
);
1218 MMonGetVersion
*m
= new MMonGetVersion();
1220 m
->handle
= ++version_req_id
;
1221 version_requests
[m
->handle
] = req
;
1222 _send_mon_message(m
);
1225 void MonClient::handle_get_version_reply(MMonGetVersionReply
* m
)
1227 ceph_assert(monc_lock
.is_locked());
1228 map
<ceph_tid_t
, version_req_d
*>::iterator iter
= version_requests
.find(m
->handle
);
1229 if (iter
== version_requests
.end()) {
1230 ldout(cct
, 0) << __func__
<< " version request with handle " << m
->handle
1231 << " not found" << dendl
;
1233 version_req_d
*req
= iter
->second
;
1234 ldout(cct
, 10) << __func__
<< " finishing " << req
<< " version " << m
->version
<< dendl
;
1235 version_requests
.erase(iter
);
1237 *req
->newest
= m
->version
;
1239 *req
->oldest
= m
->oldest_version
;
1240 finisher
.queue(req
->context
, 0);
1246 int MonClient::get_auth_request(
1248 AuthConnectionMeta
*auth_meta
,
1249 uint32_t *auth_method
,
1250 std::vector
<uint32_t> *preferred_modes
,
1253 std::lock_guard
l(monc_lock
);
1254 ldout(cct
,10) << __func__
<< " con " << con
<< " auth_method " << *auth_method
1257 // connection to mon?
1258 if (con
->get_peer_type() == CEPH_ENTITY_TYPE_MON
) {
1259 ceph_assert(!auth_meta
->authorizer
);
1260 for (auto& i
: pending_cons
) {
1261 if (i
.second
.is_con(con
)) {
1262 return i
.second
.get_auth_request(
1263 auth_method
, preferred_modes
, bl
,
1264 entity_name
, want_keys
, rotating_secrets
.get());
1270 // generate authorizer
1272 lderr(cct
) << __func__
<< " but no auth handler is set up" << dendl
;
1275 auth_meta
->authorizer
.reset(auth
->build_authorizer(con
->get_peer_type()));
1276 if (!auth_meta
->authorizer
) {
1277 lderr(cct
) << __func__
<< " failed to build_authorizer for type "
1278 << ceph_entity_type_name(con
->get_peer_type()) << dendl
;
1281 auth_meta
->auth_method
= auth_meta
->authorizer
->protocol
;
1282 auth_registry
.get_supported_modes(con
->get_peer_type(),
1283 auth_meta
->auth_method
,
1285 *bl
= auth_meta
->authorizer
->bl
;
1289 int MonClient::handle_auth_reply_more(
1291 AuthConnectionMeta
*auth_meta
,
1292 const bufferlist
& bl
,
1295 std::lock_guard
l(monc_lock
);
1297 if (con
->get_peer_type() == CEPH_ENTITY_TYPE_MON
) {
1298 for (auto& i
: pending_cons
) {
1299 if (i
.second
.is_con(con
)) {
1300 return i
.second
.handle_auth_reply_more(auth_meta
, bl
, reply
);
1306 // authorizer challenges
1307 if (!auth
|| !auth_meta
->authorizer
) {
1308 lderr(cct
) << __func__
<< " no authorizer?" << dendl
;
1311 auth_meta
->authorizer
->add_challenge(cct
, bl
);
1312 *reply
= auth_meta
->authorizer
->bl
;
1316 int MonClient::handle_auth_done(
1318 AuthConnectionMeta
*auth_meta
,
1321 const bufferlist
& bl
,
1322 CryptoKey
*session_key
,
1323 std::string
*connection_secret
)
1325 if (con
->get_peer_type() == CEPH_ENTITY_TYPE_MON
) {
1326 std::lock_guard
l(monc_lock
);
1327 for (auto& i
: pending_cons
) {
1328 if (i
.second
.is_con(con
)) {
1329 int r
= i
.second
.handle_auth_done(
1330 auth_meta
, global_id
, bl
,
1331 session_key
, connection_secret
);
1333 pending_cons
.erase(i
.first
);
1334 if (!pending_cons
.empty()) {
1338 active_con
.reset(new MonConnection(std::move(i
.second
)));
1339 pending_cons
.clear();
1340 ceph_assert(active_con
->have_session());
1344 if (r
|| monmap
.get_epoch() > 0) {
1352 // verify authorizer reply
1353 auto p
= bl
.begin();
1354 if (!auth_meta
->authorizer
->verify_reply(p
, &auth_meta
->connection_secret
)) {
1355 ldout(cct
, 0) << __func__
<< " failed verifying authorizer reply"
1359 auth_meta
->session_key
= auth_meta
->authorizer
->session_key
;
1364 int MonClient::handle_auth_bad_method(
1366 AuthConnectionMeta
*auth_meta
,
1367 uint32_t old_auth_method
,
1369 const std::vector
<uint32_t>& allowed_methods
,
1370 const std::vector
<uint32_t>& allowed_modes
)
1372 auth_meta
->allowed_methods
= allowed_methods
;
1374 std::lock_guard
l(monc_lock
);
1375 if (con
->get_peer_type() == CEPH_ENTITY_TYPE_MON
) {
1376 for (auto& i
: pending_cons
) {
1377 if (i
.second
.is_con(con
)) {
1378 int r
= i
.second
.handle_auth_bad_method(old_auth_method
,
1383 return r
; // try another method on this con
1385 pending_cons
.erase(i
.first
);
1386 if (!pending_cons
.empty()) {
1387 return r
; // fail this con, maybe another con will succeed
1398 ldout(cct
,10) << __func__
<< " hmm, they didn't like " << old_auth_method
1399 << " result " << cpp_strerror(result
)
1400 << " and auth is " << (auth
? auth
->get_protocol() : 0)
1406 int MonClient::handle_auth_request(
1408 AuthConnectionMeta
*auth_meta
,
1410 uint32_t auth_method
,
1411 const bufferlist
& payload
,
1414 auth_meta
->auth_mode
= payload
[0];
1415 if (auth_meta
->auth_mode
< AUTH_MODE_AUTHORIZER
||
1416 auth_meta
->auth_mode
> AUTH_MODE_AUTHORIZER_MAX
) {
1419 AuthAuthorizeHandler
*ah
= get_auth_authorize_handler(con
->get_peer_type(),
1422 lderr(cct
) << __func__
<< " no AuthAuthorizeHandler found for auth method "
1423 << auth_method
<< dendl
;
1427 auto ac
= &auth_meta
->authorizer_challenge
;
1428 if (!HAVE_FEATURE(con
->get_features(), CEPHX_V2
)) {
1429 if (cct
->_conf
->cephx_service_require_version
>= 2) {
1430 ldout(cct
,10) << __func__
<< " client missing CEPHX_V2 ("
1431 << "cephx_service_requre_version = "
1432 << cct
->_conf
->cephx_service_require_version
<< ")" << dendl
;
1438 bool was_challenge
= (bool)auth_meta
->authorizer_challenge
;
1439 bool isvalid
= ah
->verify_authorizer(
1441 rotating_secrets
.get(),
1443 auth_meta
->get_connection_secret_length(),
1446 &con
->peer_global_id
,
1447 &con
->peer_caps_info
,
1448 &auth_meta
->session_key
,
1449 &auth_meta
->connection_secret
,
1452 handle_authentication_dispatcher
->ms_handle_authentication(con
);
1455 if (!more
&& !was_challenge
&& auth_meta
->authorizer_challenge
) {
1456 ldout(cct
,10) << __func__
<< " added challenge on " << con
<< dendl
;
1459 ldout(cct
,10) << __func__
<< " bad authorizer on " << con
<< dendl
;
1463 AuthAuthorizer
* MonClient::build_authorizer(int service_id
) const {
1464 std::lock_guard
l(monc_lock
);
1466 return auth
->build_authorizer(service_id
);
1468 ldout(cct
, 0) << __func__
<< " for " << ceph_entity_type_name(service_id
)
1469 << ", but no auth is available now" << dendl
;
1474 #define dout_subsys ceph_subsys_monc
1476 #define dout_prefix *_dout << "monclient" << (have_session() ? ": " : "(hunting): ")
1478 MonConnection::MonConnection(
1479 CephContext
*cct
, ConnectionRef con
, uint64_t global_id
,
1481 : cct(cct
), con(con
), global_id(global_id
), auth_registry(ar
)
1484 MonConnection::~MonConnection()
1492 bool MonConnection::have_session() const
1494 return state
== State::HAVE_SESSION
;
1497 void MonConnection::start(epoch_t epoch
,
1498 const EntityName
& entity_name
)
1500 auth_start
= ceph_clock_now();
1502 if (con
->get_peer_addr().is_msgr2()) {
1503 ldout(cct
, 10) << __func__
<< " opening mon connection" << dendl
;
1504 state
= State::AUTHENTICATING
;
1505 con
->send_message(new MMonGetMap());
1509 // restart authentication handshake
1510 state
= State::NEGOTIATING
;
1512 // send an initial keepalive to ensure our timestamp is valid by the
1513 // time we are in an OPENED state (by sequencing this before
1515 con
->send_keepalive();
1518 m
->protocol
= CEPH_AUTH_UNKNOWN
;
1519 m
->monmap_epoch
= epoch
;
1521 encode(struct_v
, m
->auth_payload
);
1522 vector
<uint32_t> auth_supported
;
1523 auth_registry
->get_supported_methods(con
->get_peer_type(), &auth_supported
);
1524 encode(auth_supported
, m
->auth_payload
);
1525 encode(entity_name
, m
->auth_payload
);
1526 encode(global_id
, m
->auth_payload
);
1527 con
->send_message(m
);
1530 int MonConnection::get_auth_request(
1532 std::vector
<uint32_t> *preferred_modes
,
1534 const EntityName
& entity_name
,
1536 RotatingKeyRing
* keyring
)
1539 if (auth_method
< 0) {
1540 vector
<uint32_t> as
;
1541 auth_registry
->get_supported_methods(con
->get_peer_type(), &as
);
1545 auth_method
= as
.front();
1547 *method
= auth_method
;
1548 auth_registry
->get_supported_modes(con
->get_peer_type(), auth_method
,
1550 ldout(cct
,10) << __func__
<< " method " << *method
1551 << " preferred_modes " << *preferred_modes
<< dendl
;
1552 if (preferred_modes
->empty()) {
1559 int r
= _init_auth(*method
, entity_name
, want_keys
, keyring
, true);
1560 ceph_assert(r
== 0);
1562 // initial requset includes some boilerplate...
1563 encode((char)AUTH_MODE_MON
, *bl
);
1564 encode(entity_name
, *bl
);
1565 encode(global_id
, *bl
);
1567 // and (maybe) some method-specific initial payload
1568 auth
->build_initial_request(bl
);
1573 int MonConnection::handle_auth_reply_more(
1574 AuthConnectionMeta
*auth_meta
,
1575 const bufferlist
& bl
,
1578 ldout(cct
, 10) << __func__
<< " payload " << bl
.length() << dendl
;
1579 ldout(cct
, 30) << __func__
<< " got\n";
1583 auto p
= bl
.cbegin();
1584 ldout(cct
, 10) << __func__
<< " payload_len " << bl
.length() << dendl
;
1585 int r
= auth
->handle_response(0, p
, &auth_meta
->session_key
,
1586 &auth_meta
->connection_secret
);
1588 auth
->prepare_build_request();
1589 auth
->build_request(*reply
);
1590 ldout(cct
, 10) << __func__
<< " responding with " << reply
->length()
1591 << " bytes" << dendl
;
1594 lderr(cct
) << __func__
<< " handle_response returned " << r
<< dendl
;
1596 ldout(cct
, 10) << __func__
<< " authenticated!" << dendl
;
1598 ceph_abort(cct
, "write me");
1603 int MonConnection::handle_auth_done(
1604 AuthConnectionMeta
*auth_meta
,
1605 uint64_t new_global_id
,
1606 const bufferlist
& bl
,
1607 CryptoKey
*session_key
,
1608 std::string
*connection_secret
)
1610 ldout(cct
,10) << __func__
<< " global_id " << new_global_id
1611 << " payload " << bl
.length()
1613 global_id
= new_global_id
;
1614 auth
->set_global_id(global_id
);
1615 auto p
= bl
.begin();
1616 int auth_err
= auth
->handle_response(0, p
, &auth_meta
->session_key
,
1617 &auth_meta
->connection_secret
);
1618 if (auth_err
>= 0) {
1619 state
= State::HAVE_SESSION
;
1621 con
->set_last_keepalive_ack(auth_start
);
1625 int MonConnection::handle_auth_bad_method(
1626 uint32_t old_auth_method
,
1628 const std::vector
<uint32_t>& allowed_methods
,
1629 const std::vector
<uint32_t>& allowed_modes
)
1631 ldout(cct
,10) << __func__
<< " old_auth_method " << old_auth_method
1632 << " result " << cpp_strerror(result
)
1633 << " allowed_methods " << allowed_methods
<< dendl
;
1634 vector
<uint32_t> auth_supported
;
1635 auth_registry
->get_supported_methods(con
->get_peer_type(), &auth_supported
);
1636 auto p
= std::find(auth_supported
.begin(), auth_supported
.end(),
1638 assert(p
!= auth_supported
.end());
1639 p
= std::find_first_of(std::next(p
), auth_supported
.end(),
1640 allowed_methods
.begin(), allowed_methods
.end());
1641 if (p
== auth_supported
.end()) {
1642 lderr(cct
) << __func__
<< " server allowed_methods " << allowed_methods
1643 << " but i only support " << auth_supported
<< dendl
;
1647 ldout(cct
,10) << __func__
<< " will try " << auth_method
<< " next" << dendl
;
1651 int MonConnection::handle_auth(MAuthReply
* m
,
1652 const EntityName
& entity_name
,
1654 RotatingKeyRing
* keyring
)
1656 if (state
== State::NEGOTIATING
) {
1657 int r
= _negotiate(m
, entity_name
, want_keys
, keyring
);
1661 state
= State::AUTHENTICATING
;
1663 int r
= authenticate(m
);
1665 state
= State::HAVE_SESSION
;
1670 int MonConnection::_negotiate(MAuthReply
*m
,
1671 const EntityName
& entity_name
,
1673 RotatingKeyRing
* keyring
)
1675 if (auth
&& (int)m
->protocol
== auth
->get_protocol()) {
1676 // good, negotiation completed
1681 int r
= _init_auth(m
->protocol
, entity_name
, want_keys
, keyring
, false);
1682 if (r
== -ENOTSUP
) {
1683 if (m
->result
== -ENOTSUP
) {
1684 ldout(cct
, 10) << "none of our auth protocols are supported by the server"
1692 int MonConnection::_init_auth(
1694 const EntityName
& entity_name
,
1696 RotatingKeyRing
* keyring
,
1699 ldout(cct
,10) << __func__
<< " method " << method
<< dendl
;
1701 AuthClientHandler::create(cct
, method
, keyring
));
1703 ldout(cct
, 10) << " no handler for protocol " << method
<< dendl
;
1707 // do not request MGR key unless the mon has the SERVER_KRAKEN
1708 // feature. otherwise it will give us an auth error. note that
1709 // we have to use the FEATUREMASK because pre-jewel the kraken
1710 // feature bit was used for something else.
1712 (want_keys
& CEPH_ENTITY_TYPE_MGR
) &&
1713 !(con
->has_features(CEPH_FEATUREMASK_SERVER_KRAKEN
))) {
1714 ldout(cct
, 1) << __func__
1715 << " not requesting MGR keys from pre-kraken monitor"
1717 want_keys
&= ~CEPH_ENTITY_TYPE_MGR
;
1719 auth
->set_want_keys(want_keys
);
1720 auth
->init(entity_name
);
1721 auth
->set_global_id(global_id
);
1725 int MonConnection::authenticate(MAuthReply
*m
)
1728 if (!m
->global_id
) {
1729 ldout(cct
, 1) << "peer sent an invalid global_id" << dendl
;
1731 if (m
->global_id
!= global_id
) {
1732 // it's a new session
1734 global_id
= m
->global_id
;
1735 auth
->set_global_id(global_id
);
1736 ldout(cct
, 10) << "my global_id is " << m
->global_id
<< dendl
;
1738 auto p
= m
->result_bl
.cbegin();
1739 int ret
= auth
->handle_response(m
->result
, p
, nullptr, nullptr);
1740 if (ret
== -EAGAIN
) {
1741 auto ma
= new MAuth
;
1742 ma
->protocol
= auth
->get_protocol();
1743 auth
->prepare_build_request();
1744 auth
->build_request(ma
->auth_payload
);
1745 con
->send_message(ma
);
1750 void MonClient::register_config_callback(md_config_t::config_callback fn
) {
1751 ceph_assert(!config_cb
);
1755 md_config_t::config_callback
MonClient::get_config_callback() {