summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp36
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.h6
-rw-r--r--src/mongo/db/db.cpp10
-rw-r--r--src/mongo/db/dbdirectclient.cpp4
-rw-r--r--src/mongo/db/repl/check_quorum_for_config_change.cpp9
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args.cpp29
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args.h14
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp26
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args_v1.h18
-rw-r--r--src/mongo/db/repl/replication_info.cpp21
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl.cpp8
-rw-r--r--src/mongo/db/wire_version.h34
12 files changed, 193 insertions, 22 deletions
diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp
index 8a2ed8a54ad..9e31469fe51 100644
--- a/src/mongo/db/commands/feature_compatibility_version.cpp
+++ b/src/mongo/db/commands/feature_compatibility_version.cpp
@@ -40,6 +40,7 @@
#include "mongo/db/server_parameters.h"
#include "mongo/db/service_context.h"
#include "mongo/db/storage/storage_engine.h"
+#include "mongo/db/wire_version.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/transport/service_entry_point.h"
@@ -340,8 +341,11 @@ void FeatureCompatibilityVersion::onInsertOrUpdate(OperationContext* opCtx, cons
// version that is below the minimum.
opCtx->recoveryUnit()->onCommit([opCtx, newVersion]() {
serverGlobalParams.featureCompatibility.setVersion(newVersion);
+ updateMinWireVersion();
- // Close all connections from internal clients with binary versions lower than 3.6.
+ // Close all incoming connections from internal clients with binary versions lower than
+ // ours. It would be desirable to close all outgoing connections to servers with lower
+ // binary version, but it is not currently possible.
if (newVersion != ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
opCtx->getServiceContext()->getServiceEntryPoint()->endAllSessions(
transport::Session::kLatestVersionInternalClientKeepOpen |
@@ -367,6 +371,7 @@ void FeatureCompatibilityVersion::onDelete(OperationContext* opCtx, const BSONOb
opCtx->recoveryUnit()->onCommit([]() {
serverGlobalParams.featureCompatibility.setVersion(
ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34);
+ updateMinWireVersion();
});
}
@@ -384,9 +389,35 @@ void FeatureCompatibilityVersion::onDropCollection(OperationContext* opCtx) {
opCtx->recoveryUnit()->onCommit([]() {
serverGlobalParams.featureCompatibility.setVersion(
ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34);
+ updateMinWireVersion();
});
}
+void FeatureCompatibilityVersion::updateMinWireVersion() {
+ WireSpec& spec = WireSpec::instance();
+
+ switch (serverGlobalParams.featureCompatibility.getVersion()) {
+ case ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo36:
+ case ServerGlobalParams::FeatureCompatibility::Version::kUpgradingTo36:
+ case ServerGlobalParams::FeatureCompatibility::Version::kDowngradingTo34:
+ spec.incomingInternalClient.minWireVersion = LATEST_WIRE_VERSION;
+ spec.outgoing.minWireVersion = LATEST_WIRE_VERSION;
+ return;
+ case ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34:
+ // It would be preferable to set 'incomingInternalClient.minWireVersion' and
+ // 'outgoing.minWireVersion' to LATEST_WIRE_VERSION - 1, but this is not possible due to
+ // a bug in 3.4, where if the receiving node says it supports wire version range
+ // [COMMANDS_ACCEPT_WRITE_CONCERN, SUPPORTS_OP_MSG], the initiating node will think it
+ // only supports OP_QUERY.
+ spec.incomingInternalClient.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ return;
+ case ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault34Behavior:
+ // getVersion() does not return this value.
+ MONGO_UNREACHABLE;
+ }
+}
+
void FeatureCompatibilityVersion::_validateVersion(StringData version) {
uassert(40284,
str::stream() << "featureCompatibilityVersion must be '"
@@ -471,7 +502,8 @@ public:
FeatureCompatibilityVersion::kTargetVersionField,
FeatureCompatibilityVersionCommandParser::kVersion34);
return;
- default:
+ case ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault34Behavior:
+ // getVersion() does not return this value.
MONGO_UNREACHABLE;
}
}
diff --git a/src/mongo/db/commands/feature_compatibility_version.h b/src/mongo/db/commands/feature_compatibility_version.h
index e1598756919..70acd034ef3 100644
--- a/src/mongo/db/commands/feature_compatibility_version.h
+++ b/src/mongo/db/commands/feature_compatibility_version.h
@@ -134,6 +134,12 @@ public:
*/
static void onDropCollection(OperationContext* opCtx);
+ /**
+ * Sets the server's outgoing and incomingInternalClient minWireVersions according to the
+ * current featureCompatibilityVersion value.
+ */
+ static void updateMinWireVersion();
+
private:
/**
* Validate version. Uasserts if invalid.
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index b18a5b40010..2d191c38220 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -546,6 +546,7 @@ StatusWith<bool> repairDatabasesAndCheckVersion(OperationContext* opCtx) {
fcvDocumentExists = true;
auto version = swVersion.getValue();
serverGlobalParams.featureCompatibility.setVersion(version);
+ FeatureCompatibilityVersion::updateMinWireVersion();
// On startup, if the version is in an upgrading or downrading state, print a
// warning.
@@ -662,6 +663,15 @@ StatusWith<bool> repairDatabasesAndCheckVersion(OperationContext* opCtx) {
void initWireSpec() {
WireSpec& spec = WireSpec::instance();
+ // The featureCompatibilityVersion behavior defaults to the downgrade behavior while the
+ // in-memory version is unset.
+
+ spec.incomingInternalClient.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.incomingInternalClient.maxWireVersion = LATEST_WIRE_VERSION;
+
+ spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
+ spec.outgoing.maxWireVersion = LATEST_WIRE_VERSION;
+
spec.isInternalClient = true;
}
diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp
index c644f2dd631..132a01131ce 100644
--- a/src/mongo/db/dbdirectclient.cpp
+++ b/src/mongo/db/dbdirectclient.cpp
@@ -95,12 +95,12 @@ std::string DBDirectClient::getServerAddress() const {
// Returned version should match the incoming connections restrictions.
int DBDirectClient::getMinWireVersion() {
- return WireSpec::instance().incoming.minWireVersion;
+ return WireSpec::instance().incomingExternalClient.minWireVersion;
}
// Returned version should match the incoming connections restrictions.
int DBDirectClient::getMaxWireVersion() {
- return WireSpec::instance().incoming.maxWireVersion;
+ return WireSpec::instance().incomingExternalClient.maxWireVersion;
}
bool DBDirectClient::isReplicaSetMember() const {
diff --git a/src/mongo/db/repl/check_quorum_for_config_change.cpp b/src/mongo/db/repl/check_quorum_for_config_change.cpp
index 83489872c63..e1a2321d91e 100644
--- a/src/mongo/db/repl/check_quorum_for_config_change.cpp
+++ b/src/mongo/db/repl/check_quorum_for_config_change.cpp
@@ -40,6 +40,7 @@
#include "mongo/db/repl/repl_set_heartbeat_response.h"
#include "mongo/db/repl/scatter_gather_algorithm.h"
#include "mongo/db/repl/scatter_gather_runner.h"
+#include "mongo/db/server_options.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
#include "mongo/util/log.h"
#include "mongo/util/mongoutils/str.h"
@@ -89,6 +90,10 @@ std::vector<RemoteCommandRequest> QuorumChecker::getRequests() const {
hbArgs.setSetName(_rsConfig->getReplSetName());
hbArgs.setProtocolVersion(1);
hbArgs.setConfigVersion(_rsConfig->getConfigVersion());
+ if (serverGlobalParams.featureCompatibility.getVersion() !=
+ ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
+ hbArgs.setHeartbeatVersion(1);
+ }
hbArgs.setCheckEmpty(isInitialConfig);
hbArgs.setSenderHost(myConfig.getHostAndPort());
hbArgs.setSenderId(myConfig.getId());
@@ -98,6 +103,10 @@ std::vector<RemoteCommandRequest> QuorumChecker::getRequests() const {
ReplSetHeartbeatArgsV1 hbArgs;
hbArgs.setSetName(_rsConfig->getReplSetName());
hbArgs.setConfigVersion(_rsConfig->getConfigVersion());
+ if (serverGlobalParams.featureCompatibility.getVersion() !=
+ ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
+ hbArgs.setHeartbeatVersion(1);
+ }
if (isInitialConfig) {
hbArgs.setCheckEmpty();
}
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args.cpp b/src/mongo/db/repl/repl_set_heartbeat_args.cpp
index db88f7e47b6..5b75f97c516 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args.cpp
+++ b/src/mongo/db/repl/repl_set_heartbeat_args.cpp
@@ -42,6 +42,7 @@ namespace {
const std::string kCheckEmptyFieldName = "checkEmpty";
const std::string kProtocolVersionFieldName = "pv";
const std::string kConfigVersionFieldName = "v";
+const std::string kHeartbeatVersionFieldName = "hbv";
const std::string kSenderIdFieldName = "fromId";
const std::string kSetNameFieldName = "replSetHeartbeat";
const std::string kSenderHostFieldName = "from";
@@ -49,6 +50,7 @@ const std::string kSenderHostFieldName = "from";
const std::string kLegalHeartbeatFieldNames[] = {kCheckEmptyFieldName,
kProtocolVersionFieldName,
kConfigVersionFieldName,
+ kHeartbeatVersionFieldName,
kSenderIdFieldName,
kSetNameFieldName,
kSenderHostFieldName};
@@ -59,12 +61,14 @@ ReplSetHeartbeatArgs::ReplSetHeartbeatArgs()
: _hasCheckEmpty(false),
_hasProtocolVersion(false),
_hasConfigVersion(false),
+ _hasHeartbeatVersion(false),
_hasSenderId(false),
_hasSetName(false),
_hasSenderHost(false),
_checkEmpty(false),
_protocolVersion(-1),
_configVersion(-1),
+ _heartbeatVersion(-1),
_senderId(-1),
_setName(""),
_senderHost(HostAndPort()) {}
@@ -90,6 +94,22 @@ Status ReplSetHeartbeatArgs::initialize(const BSONObj& argsObj) {
return status;
_hasConfigVersion = true;
+ long long tempHeartbeatVersion;
+ status = bsonExtractIntegerField(argsObj, kHeartbeatVersionFieldName, &tempHeartbeatVersion);
+ if (status.isOK()) {
+ if (tempHeartbeatVersion != 1) {
+ return Status(ErrorCodes::Error(40665),
+ str::stream() << "Found invalid value for field "
+ << kHeartbeatVersionFieldName
+ << ": "
+ << tempHeartbeatVersion);
+ }
+ _heartbeatVersion = tempHeartbeatVersion;
+ _hasHeartbeatVersion = true;
+ } else if (status.code() != ErrorCodes::NoSuchKey) {
+ return status;
+ }
+
status = bsonExtractIntegerFieldWithDefault(argsObj, kSenderIdFieldName, -1, &_senderId);
if (!status.isOK())
return status;
@@ -126,6 +146,10 @@ BSONObj ReplSetHeartbeatArgs::toBSON() const {
builder.append("replSetHeartbeat", _setName);
builder.appendIntOrLL("pv", _protocolVersion);
builder.appendIntOrLL("v", _configVersion);
+ if (_hasHeartbeatVersion) {
+ builder.append("hbv", _heartbeatVersion);
+ }
+
builder.append("from", _hasSenderHost ? _senderHost.toString() : "");
if (_hasSenderId) {
@@ -152,6 +176,11 @@ void ReplSetHeartbeatArgs::setConfigVersion(long long newVal) {
_hasConfigVersion = true;
}
+void ReplSetHeartbeatArgs::setHeartbeatVersion(long long newVal) {
+ _heartbeatVersion = newVal;
+ _hasHeartbeatVersion = true;
+}
+
void ReplSetHeartbeatArgs::setSenderId(long long newVal) {
_senderId = newVal;
_hasSenderId = true;
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args.h b/src/mongo/db/repl/repl_set_heartbeat_args.h
index 1faa7d4bca0..40e8e180312 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args.h
+++ b/src/mongo/db/repl/repl_set_heartbeat_args.h
@@ -78,6 +78,14 @@ public:
}
/**
+ * Gets the heartbeat version number of the sender. This field was added to ensure that
+ * heartbeats sent from featureCompatibilityVersion 3.6 nodes to binary version 3.4 nodes fail.
+ */
+ long long getHeartbeatVersion() const {
+ return _heartbeatVersion;
+ }
+
+ /**
* Gets the _id of the sender in their ReplSetConfig.
*/
long long getSenderId() const {
@@ -110,6 +118,9 @@ public:
bool hasConfigVersion() const {
return _hasConfigVersion;
}
+ bool hasHeartbeatVersion() const {
+ return _hasHeartbeatVersion;
+ }
bool hasSenderId() const {
return _hasSenderId;
}
@@ -126,6 +137,7 @@ public:
void setCheckEmpty(bool newVal);
void setProtocolVersion(long long newVal);
void setConfigVersion(long long newVal);
+ void setHeartbeatVersion(long long newVal);
void setSenderId(long long newVal);
void setSetName(std::string newVal);
void setSenderHost(HostAndPort newVal);
@@ -141,6 +153,7 @@ private:
bool _hasCheckEmpty;
bool _hasProtocolVersion;
bool _hasConfigVersion;
+ bool _hasHeartbeatVersion;
bool _hasSenderId;
bool _hasSetName;
bool _hasSenderHost;
@@ -149,6 +162,7 @@ private:
bool _checkEmpty;
long long _protocolVersion;
long long _configVersion;
+ long long _heartbeatVersion;
long long _senderId;
std::string _setName;
HostAndPort _senderHost;
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp b/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
index 39bab8cdda7..4568e3ef89c 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
+++ b/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
@@ -42,6 +42,7 @@ namespace {
const std::string kCheckEmptyFieldName = "checkEmpty";
const std::string kConfigVersionFieldName = "configVersion";
+const std::string kHeartbeatVersionFieldName = "hbv";
const std::string kSenderHostFieldName = "from";
const std::string kSenderIdFieldName = "fromId";
const std::string kSetNameFieldName = "replSetHeartbeat";
@@ -49,6 +50,7 @@ const std::string kTermFieldName = "term";
const std::string kLegalHeartbeatFieldNames[] = {kCheckEmptyFieldName,
kConfigVersionFieldName,
+ kHeartbeatVersionFieldName,
kSenderHostFieldName,
kSenderIdFieldName,
kSetNameFieldName,
@@ -70,6 +72,22 @@ Status ReplSetHeartbeatArgsV1::initialize(const BSONObj& argsObj) {
if (!status.isOK())
return status;
+ long long tempHeartbeatVersion;
+ status = bsonExtractIntegerField(argsObj, kHeartbeatVersionFieldName, &tempHeartbeatVersion);
+ if (status.isOK()) {
+ if (tempHeartbeatVersion != 1) {
+ return Status(ErrorCodes::Error(40666),
+ str::stream() << "Found invalid value for field "
+ << kHeartbeatVersionFieldName
+ << ": "
+ << tempHeartbeatVersion);
+ }
+ _heartbeatVersion = tempHeartbeatVersion;
+ _hasHeartbeatVersion = true;
+ } else if (status.code() != ErrorCodes::NoSuchKey) {
+ return status;
+ }
+
status = bsonExtractIntegerFieldWithDefault(argsObj, kSenderIdFieldName, -1, &_senderId);
if (!status.isOK())
return status;
@@ -104,6 +122,11 @@ void ReplSetHeartbeatArgsV1::setConfigVersion(long long newVal) {
_configVersion = newVal;
}
+void ReplSetHeartbeatArgsV1::setHeartbeatVersion(long long newVal) {
+ _heartbeatVersion = newVal;
+ _hasHeartbeatVersion = true;
+}
+
void ReplSetHeartbeatArgsV1::setSenderHost(const HostAndPort& newVal) {
_senderHost = newVal;
_hasSender = true;
@@ -138,6 +161,9 @@ void ReplSetHeartbeatArgsV1::addToBSON(BSONObjBuilder* builder) const {
builder->append(kCheckEmptyFieldName, _checkEmpty);
}
builder->appendIntOrLL(kConfigVersionFieldName, _configVersion);
+ if (_hasHeartbeatVersion) {
+ builder->appendIntOrLL(kHeartbeatVersionFieldName, _hasHeartbeatVersion);
+ }
builder->append(kSenderHostFieldName, _hasSender ? _senderHost.toString() : "");
builder->appendIntOrLL(kSenderIdFieldName, _senderId);
builder->appendIntOrLL(kTermFieldName, _term);
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args_v1.h b/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
index 45a00ab8927..6f1cbb94af8 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
+++ b/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
@@ -63,6 +63,14 @@ public:
}
/**
+ * Gets the heartbeat version number of the sender. This field was added to ensure that
+ * heartbeats sent from featureCompatibilityVersion 3.6 nodes to binary version 3.4 nodes fail.
+ */
+ long long getHeartbeatVersion() const {
+ return _heartbeatVersion;
+ }
+
+ /**
* Gets the _id of the sender in their ReplSetConfig.
*/
long long getSenderId() const {
@@ -105,9 +113,17 @@ public:
}
/**
+ * Returns whether or not the heartbeat version of the sender is set.
+ */
+ bool hasHeartbeatVersion() const {
+ return _hasHeartbeatVersion;
+ }
+
+ /**
* The below methods set the value in the method name to 'newVal'.
*/
void setConfigVersion(long long newVal);
+ void setHeartbeatVersion(long long newVal);
void setSenderId(long long newVal);
void setSenderHost(const HostAndPort& newVal);
void setSetName(const std::string& newVal);
@@ -126,10 +142,12 @@ public:
private:
// look at the body of the isInitialized() function to see which fields are mandatory
long long _configVersion = -1;
+ long long _heartbeatVersion = -1;
long long _senderId = -1;
long long _term = -1;
bool _checkEmpty = false;
bool _hasSender = false;
+ bool _hasHeartbeatVersion = false;
std::string _setName;
HostAndPort _senderHost;
};
diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp
index 192d7c67b22..7729eaccda3 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -309,7 +309,8 @@ public:
// All incoming connections from mongod/mongos of earlier versions should be
// closed if the featureCompatibilityVersion is bumped to 3.6.
- if (elem.numberInt() >= WireSpec::instance().incoming.maxWireVersion) {
+ if (elem.numberInt() >=
+ WireSpec::instance().incomingInternalClient.maxWireVersion) {
sessionTagsToSet |=
transport::Session::kLatestVersionInternalClientKeepOpen;
} else {
@@ -361,18 +362,18 @@ public:
result.appendNumber("maxMessageSizeBytes", MaxMessageSizeBytes);
result.appendNumber("maxWriteBatchSize", write_ops::kMaxWriteBatchSize);
result.appendDate("localTime", jsTime());
- result.append("maxWireVersion", WireSpec::instance().incoming.maxWireVersion);
result.append("logicalSessionTimeoutMinutes", localLogicalSessionTimeoutMinutes);
- // If the featureCompatibilityVersion is 3.6 (or upgrading or downgrading), respond with
- // minWireVersion=maxWireVersion. Then if the connection is from a mongod/mongos of an
- // earlier version, it will fail to connect.
- if (internalClientElement &&
- serverGlobalParams.featureCompatibility.getVersion() !=
- ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
- result.append("minWireVersion", WireSpec::instance().incoming.maxWireVersion);
+ if (internalClientElement) {
+ result.append("minWireVersion",
+ WireSpec::instance().incomingInternalClient.minWireVersion);
+ result.append("maxWireVersion",
+ WireSpec::instance().incomingInternalClient.maxWireVersion);
} else {
- result.append("minWireVersion", WireSpec::instance().incoming.minWireVersion);
+ result.append("minWireVersion",
+ WireSpec::instance().incomingExternalClient.minWireVersion);
+ result.append("maxWireVersion",
+ WireSpec::instance().incomingExternalClient.maxWireVersion);
}
result.append("readOnly", storageGlobalParams.readOnly);
diff --git a/src/mongo/db/repl/topology_coordinator_impl.cpp b/src/mongo/db/repl/topology_coordinator_impl.cpp
index 00ec2910226..07ec8c6a99d 100644
--- a/src/mongo/db/repl/topology_coordinator_impl.cpp
+++ b/src/mongo/db/repl/topology_coordinator_impl.cpp
@@ -902,6 +902,10 @@ std::pair<ReplSetHeartbeatArgs, Milliseconds> TopologyCoordinatorImpl::prepareHe
hbArgs.setSetName(ourSetName);
hbArgs.setConfigVersion(-2);
}
+ if (serverGlobalParams.featureCompatibility.getVersion() !=
+ ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
+ hbArgs.setHeartbeatVersion(1);
+ }
const Milliseconds timeoutPeriod(
_rsConfig.isInitialized() ? _rsConfig.getHeartbeatTimeoutPeriodMillis()
@@ -938,6 +942,10 @@ std::pair<ReplSetHeartbeatArgsV1, Milliseconds> TopologyCoordinatorImpl::prepare
hbArgs.setConfigVersion(-2);
hbArgs.setTerm(OpTime::kInitialTerm);
}
+ if (serverGlobalParams.featureCompatibility.getVersion() !=
+ ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo34) {
+ hbArgs.setHeartbeatVersion(1);
+ }
const Milliseconds timeoutPeriod(
_rsConfig.isInitialized() ? _rsConfig.getHeartbeatTimeoutPeriodMillis()
diff --git a/src/mongo/db/wire_version.h b/src/mongo/db/wire_version.h
index 84b353a1d83..cc6050b8834 100644
--- a/src/mongo/db/wire_version.h
+++ b/src/mongo/db/wire_version.h
@@ -107,16 +107,34 @@ struct WireSpec {
static void appendInternalClientWireVersion(WireVersionInfo wireVersionInfo,
BSONObjBuilder* builder);
- // incoming.minWireVersion - Minimum version that the server accepts on incoming requests. We
- // should bump this whenever we don't want to allow incoming connections from clients that are
- // too old.
-
- // incoming.maxWireVersion - Latest version that the server accepts on incoming requests. This
- // should always be at the latest entry in WireVersion.
- WireVersionInfo incoming = {RELEASE_2_4_AND_BEFORE, LATEST_WIRE_VERSION};
+ // incomingExternalClient.minWireVersion - Minimum version that the server accepts on incoming
+ // requests from external clients. We should bump this whenever we don't want to allow incoming
+ // connections from clients that are too old.
+
+ // incomingExternalClient.maxWireVersion - Latest version that the server accepts on incoming
+ // requests from external clients. This should always be at the latest entry in WireVersion.
+ WireVersionInfo incomingExternalClient = {RELEASE_2_4_AND_BEFORE, LATEST_WIRE_VERSION};
+
+ // incomingInternalClient.minWireVersion - Minimum version that the server accepts on incoming
+ // requests from internal clients. This should be incomingInternalClient.maxWireVersion - 1,
+ // when the featureCompatibilityVersion is equal to the downgrade version, and
+ // incomingInternalClient.maxWireVersion otherwise. However, in 3.6, this needs to be
+ // RELEASE_2_4_AND_BEFORE when the featureCompatibilityVersion is equal to the downgrade version
+ // due to a bug in 3.4, where if the receiving node says it supports wire version range
+ // [COMMANDS_ACCEPT_WRITE_CONCERN, SUPPORTS_OP_MSG] and it is a mongod, the initiating node will
+ // think it only supports OP_QUERY.
+
+ // incomingInternalClient.maxWireVersion - Latest version that the server accepts on incoming
+ // requests. This should always be at the latest entry in WireVersion.
+ WireVersionInfo incomingInternalClient = {RELEASE_2_4_AND_BEFORE, LATEST_WIRE_VERSION};
// outgoing.minWireVersion - Minimum version allowed on remote nodes when the server sends
- // requests. We should bump this whenever we don't want to connect to clients that are too old.
+ // requests. This should be outgoing.maxWireVersion - 1, when the featureCompatibilityVersion is
+ // equal to the downgrade version, and outgoing.maxWireVersion otherwise. However, in 3.6, this
+ // needs to be RELEASE_2_4_AND_BEFORE when the featureCompatibilityVersion is equal to the
+ // downgrade version due to a bug in 3.4, where if the receiving node says it supports wire
+ // version range [COMMANDS_ACCEPT_WRITE_CONCERN, SUPPORTS_OP_MSG] and it is a mongod, the
+ // initiating node will think it only supports OP_QUERY.
// outgoing.maxWireVersion - Latest version allowed on remote nodes when the server sends
// requests.