CASSJAVA-92: Local DC provided for nodetool clientstats
patch by Lukasz Antoniak; reviewed by Bret McGuire and Abe Ratnofsky for CASSJAVA-92
diff --git a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java
index d890ae6..de0d9db 100644
--- a/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java
+++ b/core/src/main/java/com/datastax/oss/driver/api/core/loadbalancing/LoadBalancingPolicy.java
@@ -24,6 +24,7 @@
 import com.datastax.oss.driver.api.core.tracker.RequestTracker;
 import edu.umd.cs.findbugs.annotations.NonNull;
 import edu.umd.cs.findbugs.annotations.Nullable;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Queue;
@@ -76,6 +77,12 @@
    */
   void init(@NonNull Map<UUID, Node> nodes, @NonNull DistanceReporter distanceReporter);
 
+  /** Returns map containing details that impact C* node connectivity. */
+  @NonNull
+  default Map<String, ?> getStartupConfiguration() {
+    return Collections.emptyMap();
+  }
+
   /**
    * Returns the coordinators to use for a new query.
    *
diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java
index a24b632..0d7db27 100644
--- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java
+++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContext.java
@@ -216,8 +216,8 @@
       new LazyReference<>("metricIdGenerator", this::buildMetricIdGenerator, cycleDetector);
   private final LazyReference<RequestThrottler> requestThrottlerRef =
       new LazyReference<>("requestThrottler", this::buildRequestThrottler, cycleDetector);
-  private final LazyReference<Map<String, String>> startupOptionsRef =
-      new LazyReference<>("startupOptions", this::buildStartupOptions, cycleDetector);
+  private final LazyReference<StartupOptionsBuilder> startupOptionsRef =
+      new LazyReference<>("startupOptionsFactory", this::buildStartupOptionsFactory, cycleDetector);
   private final LazyReference<NodeStateListener> nodeStateListenerRef;
   private final LazyReference<SchemaChangeListener> schemaChangeListenerRef;
   private final LazyReference<RequestTracker> requestTrackerRef;
@@ -335,16 +335,15 @@
   }
 
   /**
-   * Builds a map of options to send in a Startup message.
+   * Returns builder of options to send in a Startup message.
    *
    * @see #getStartupOptions()
    */
-  protected Map<String, String> buildStartupOptions() {
+  protected StartupOptionsBuilder buildStartupOptionsFactory() {
     return new StartupOptionsBuilder(this)
         .withClientId(startupClientId)
         .withApplicationName(startupApplicationName)
-        .withApplicationVersion(startupApplicationVersion)
-        .build();
+        .withApplicationVersion(startupApplicationVersion);
   }
 
   protected Map<String, LoadBalancingPolicy> buildLoadBalancingPolicies() {
@@ -1013,7 +1012,8 @@
   @NonNull
   @Override
   public Map<String, String> getStartupOptions() {
-    return startupOptionsRef.get();
+    // startup options are calculated dynamically and may vary per connection
+    return startupOptionsRef.get().build();
   }
 
   protected RequestLogFormatter buildRequestLogFormatter() {
diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java b/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java
index 684d6b0..89a9266 100644
--- a/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java
+++ b/core/src/main/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilder.java
@@ -19,24 +19,34 @@
 
 import com.datastax.dse.driver.api.core.config.DseDriverOption;
 import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
+import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy;
 import com.datastax.oss.driver.api.core.session.Session;
 import com.datastax.oss.driver.api.core.uuid.Uuids;
+import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
 import com.datastax.oss.protocol.internal.request.Startup;
 import com.datastax.oss.protocol.internal.util.collection.NullAllowingImmutableMap;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import edu.umd.cs.findbugs.annotations.Nullable;
 import java.util.Map;
+import java.util.Optional;
 import java.util.UUID;
 import net.jcip.annotations.Immutable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @Immutable
 public class StartupOptionsBuilder {
 
   public static final String DRIVER_NAME_KEY = "DRIVER_NAME";
   public static final String DRIVER_VERSION_KEY = "DRIVER_VERSION";
+  public static final String DRIVER_BAGGAGE = "DRIVER_BAGGAGE";
   public static final String APPLICATION_NAME_KEY = "APPLICATION_NAME";
   public static final String APPLICATION_VERSION_KEY = "APPLICATION_VERSION";
   public static final String CLIENT_ID_KEY = "CLIENT_ID";
 
+  private static final Logger LOG = LoggerFactory.getLogger(StartupOptionsBuilder.class);
+  private static final ObjectMapper mapper = new ObjectMapper();
+
   protected final InternalDriverContext context;
   private UUID clientId;
   private String applicationName;
@@ -119,6 +129,7 @@
     if (applicationVersion != null) {
       builder.put(APPLICATION_VERSION_KEY, applicationVersion);
     }
+    driverBaggage().ifPresent(s -> builder.put(DRIVER_BAGGAGE, s));
 
     return builder.build();
   }
@@ -142,4 +153,21 @@
   protected String getDriverVersion() {
     return Session.OSS_DRIVER_COORDINATES.getVersion().toString();
   }
+
+  private Optional<String> driverBaggage() {
+    ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
+    for (Map.Entry<String, LoadBalancingPolicy> entry :
+        context.getLoadBalancingPolicies().entrySet()) {
+      Map<String, ?> config = entry.getValue().getStartupConfiguration();
+      if (!config.isEmpty()) {
+        builder.put(entry.getKey(), config);
+      }
+    }
+    try {
+      return Optional.of(mapper.writeValueAsString(builder.build()));
+    } catch (Exception e) {
+      LOG.warn("Failed to construct startup driver baggage", e);
+      return Optional.empty();
+    }
+  }
 }
diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java
index 587ef41..a02a5eb 100644
--- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java
+++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java
@@ -45,6 +45,7 @@
 import com.datastax.oss.driver.internal.core.util.collection.QueryPlan;
 import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
 import com.datastax.oss.driver.shaded.guava.common.base.Predicates;
+import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
 import com.datastax.oss.driver.shaded.guava.common.collect.Lists;
 import com.datastax.oss.driver.shaded.guava.common.collect.Sets;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -155,10 +156,38 @@
    * Before initialization, this method always returns null.
    */
   @Nullable
-  protected String getLocalDatacenter() {
+  public String getLocalDatacenter() {
     return localDc;
   }
 
+  @NonNull
+  @Override
+  public Map<String, ?> getStartupConfiguration() {
+    ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
+    if (localDc != null) {
+      builder.put("localDc", localDc);
+    } else {
+      // Local data center may not be discovered prior to connection pool initialization.
+      // In such scenario, return configured local data center name.
+      // Note that when using DC inferring load balancing policy, startup configuration
+      // may not show local DC name, because it will be discovered only once control connection
+      // is established and datacenter of contact points known.
+      Optional<String> configuredDc =
+          new OptionalLocalDcHelper(context, profile, logPrefix).configuredLocalDc();
+      configuredDc.ifPresent(d -> builder.put("localDc", d));
+    }
+    if (!preferredRemoteDcs.isEmpty()) {
+      builder.put("preferredRemoteDcs", preferredRemoteDcs);
+    }
+    if (allowDcFailoverForLocalCl) {
+      builder.put("allowDcFailoverForLocalCl", allowDcFailoverForLocalCl);
+    }
+    if (maxNodesPerRemoteDc > 0) {
+      builder.put("maxNodesPerRemoteDc", maxNodesPerRemoteDc);
+    }
+    return ImmutableMap.of(BasicLoadBalancingPolicy.class.getSimpleName(), builder.build());
+  }
+
   /** @return The nodes currently considered as live. */
   protected NodeSet getLiveNodes() {
     return liveNodes;
diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java
index 0f03cbb..9c31b60 100644
--- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java
+++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/DefaultLoadBalancingPolicy.java
@@ -34,6 +34,7 @@
 import com.datastax.oss.driver.internal.core.util.collection.QueryPlan;
 import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
 import com.datastax.oss.driver.shaded.guava.common.annotations.VisibleForTesting;
+import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
 import com.datastax.oss.driver.shaded.guava.common.collect.MapMaker;
 import edu.umd.cs.findbugs.annotations.NonNull;
 import edu.umd.cs.findbugs.annotations.Nullable;
@@ -350,4 +351,13 @@
       return this.oldest - threshold >= 0;
     }
   }
+
+  @NonNull
+  @Override
+  public Map<String, ?> getStartupConfiguration() {
+    Map<String, ?> parent = super.getStartupConfiguration();
+    return ImmutableMap.of(
+        DefaultLoadBalancingPolicy.class.getSimpleName(),
+        parent.get(BasicLoadBalancingPolicy.class.getSimpleName()));
+  }
 }
diff --git a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java
index d470f96..c6143f3 100644
--- a/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java
+++ b/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/helper/OptionalLocalDcHelper.java
@@ -65,20 +65,14 @@
   @Override
   @NonNull
   public Optional<String> discoverLocalDc(@NonNull Map<UUID, Node> nodes) {
-    String localDc = context.getLocalDatacenter(profile.getName());
-    if (localDc != null) {
-      LOG.debug("[{}] Local DC set programmatically: {}", logPrefix, localDc);
-      checkLocalDatacenterCompatibility(localDc, context.getMetadataManager().getContactPoints());
-      return Optional.of(localDc);
-    } else if (profile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) {
-      localDc = profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER);
-      LOG.debug("[{}] Local DC set from configuration: {}", logPrefix, localDc);
-      checkLocalDatacenterCompatibility(localDc, context.getMetadataManager().getContactPoints());
-      return Optional.of(localDc);
+    Optional<String> localDc = configuredLocalDc();
+    if (localDc.isPresent()) {
+      checkLocalDatacenterCompatibility(
+          localDc.get(), context.getMetadataManager().getContactPoints());
     } else {
       LOG.debug("[{}] Local DC not set, DC awareness will be disabled", logPrefix);
-      return Optional.empty();
     }
+    return localDc;
   }
 
   /**
@@ -138,4 +132,19 @@
     }
     return String.join(", ", new TreeSet<>(l));
   }
+
+  /** @return Local data center set programmatically or from configuration file. */
+  @NonNull
+  public Optional<String> configuredLocalDc() {
+    String localDc = context.getLocalDatacenter(profile.getName());
+    if (localDc != null) {
+      LOG.debug("[{}] Local DC set programmatically: {}", logPrefix, localDc);
+      return Optional.of(localDc);
+    } else if (profile.isDefined(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)) {
+      localDc = profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER);
+      LOG.debug("[{}] Local DC set from configuration: {}", logPrefix, localDc);
+      return Optional.of(localDc);
+    }
+    return Optional.empty();
+  }
 }
diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java
index 9280099..3bb9c4b 100644
--- a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java
+++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/FixedHostNameAddressTranslatorTest.java
@@ -26,7 +26,6 @@
 import com.datastax.oss.driver.internal.core.context.DefaultDriverContext;
 import com.datastax.oss.driver.internal.core.context.MockedDriverContextFactory;
 import java.net.InetSocketAddress;
-import java.util.Optional;
 import org.junit.Test;
 
 public class FixedHostNameAddressTranslatorTest {
@@ -36,7 +35,7 @@
     DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class);
     when(defaultProfile.getString(ADDRESS_TRANSLATOR_ADVERTISED_HOSTNAME)).thenReturn("myaddress");
     DefaultDriverContext defaultDriverContext =
-        MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile));
+        MockedDriverContextFactory.defaultDriverContext(defaultProfile);
 
     FixedHostNameAddressTranslator translator =
         new FixedHostNameAddressTranslator(defaultDriverContext);
diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java
index 2aa6ae7..4201706 100644
--- a/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java
+++ b/core/src/test/java/com/datastax/oss/driver/internal/core/addresstranslation/SubnetAddressTranslatorTest.java
@@ -30,7 +30,6 @@
 import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
 import java.net.InetSocketAddress;
 import java.util.Map;
-import java.util.Optional;
 import org.junit.Test;
 
 @SuppressWarnings("resource")
@@ -148,6 +147,6 @@
   private static DefaultDriverContext context(Map<String, String> subnetAddresses) {
     DriverExecutionProfile profile = mock(DriverExecutionProfile.class);
     when(profile.getStringMap(ADDRESS_TRANSLATOR_SUBNET_ADDRESSES)).thenReturn(subnetAddresses);
-    return MockedDriverContextFactory.defaultDriverContext(Optional.of(profile));
+    return MockedDriverContextFactory.defaultDriverContext(profile);
   }
 }
diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java
index baf1015..6d4585c 100644
--- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java
+++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/DefaultDriverContextTest.java
@@ -42,7 +42,7 @@
     DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class);
     when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none"))
         .thenReturn(compressionOption.orElse("none"));
-    return MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile));
+    return MockedDriverContextFactory.defaultDriverContext(defaultProfile);
   }
 
   private void doCreateCompressorTest(Optional<String> configVal, Class<?> expectedClz) {
diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java
index 0681732..a8b2519 100644
--- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java
+++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/MockedDriverContextFactory.java
@@ -24,44 +24,45 @@
 import com.datastax.oss.driver.api.core.config.DriverConfig;
 import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
 import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
+import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy;
+import com.datastax.oss.driver.api.core.loadbalancing.NodeDistanceEvaluator;
+import com.datastax.oss.driver.api.core.metadata.Node;
 import com.datastax.oss.driver.api.core.metadata.NodeStateListener;
 import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener;
 import com.datastax.oss.driver.api.core.session.ProgrammaticArguments;
 import com.datastax.oss.driver.api.core.tracker.RequestTracker;
+import com.datastax.oss.driver.internal.core.ConsistencyLevelRegistry;
+import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy;
+import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
 import com.datastax.oss.driver.shaded.guava.common.collect.Maps;
+import edu.umd.cs.findbugs.annotations.NonNull;
+import edu.umd.cs.findbugs.annotations.Nullable;
 import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.UUID;
 
 public class MockedDriverContextFactory {
 
   public static DefaultDriverContext defaultDriverContext() {
-    return defaultDriverContext(Optional.empty());
+    return defaultDriverContext(MockedDriverContextFactory.defaultProfile("datacenter1"));
   }
 
   public static DefaultDriverContext defaultDriverContext(
-      Optional<DriverExecutionProfile> profileOption) {
-
-    /* If the caller provided a profile use that, otherwise make a new one */
-    final DriverExecutionProfile profile =
-        profileOption.orElseGet(
-            () -> {
-              DriverExecutionProfile blankProfile = mock(DriverExecutionProfile.class);
-              when(blankProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none"))
-                  .thenReturn("none");
-              when(blankProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER))
-                  .thenReturn(Duration.ofMinutes(5));
-              when(blankProfile.isDefined(DefaultDriverOption.METRICS_FACTORY_CLASS))
-                  .thenReturn(true);
-              when(blankProfile.getString(DefaultDriverOption.METRICS_FACTORY_CLASS))
-                  .thenReturn("DefaultMetricsFactory");
-              return blankProfile;
-            });
+      DriverExecutionProfile defaultProfile, DriverExecutionProfile... profiles) {
 
     /* Setup machinery to connect the input DriverExecutionProfile to the config loader */
     final DriverConfig driverConfig = mock(DriverConfig.class);
     final DriverConfigLoader configLoader = mock(DriverConfigLoader.class);
     when(configLoader.getInitialConfig()).thenReturn(driverConfig);
-    when(driverConfig.getDefaultProfile()).thenReturn(profile);
+    when(driverConfig.getDefaultProfile()).thenReturn(defaultProfile);
+    when(driverConfig.getProfile(defaultProfile.getName())).thenReturn(defaultProfile);
+
+    for (DriverExecutionProfile profile : profiles) {
+      when(driverConfig.getProfile(profile.getName())).thenReturn(profile);
+    }
 
     ProgrammaticArguments args =
         ProgrammaticArguments.builder()
@@ -71,6 +72,89 @@
             .withLocalDatacenters(Maps.newHashMap())
             .withNodeDistanceEvaluators(Maps.newHashMap())
             .build();
-    return new DefaultDriverContext(configLoader, args);
+
+    return new DefaultDriverContext(configLoader, args) {
+      @NonNull
+      @Override
+      public Map<String, LoadBalancingPolicy> getLoadBalancingPolicies() {
+        ImmutableMap.Builder<String, LoadBalancingPolicy> map = ImmutableMap.builder();
+        map.put(
+            defaultProfile.getName(),
+            mockLoadBalancingPolicy(
+                this,
+                defaultProfile.getName(),
+                defaultProfile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)));
+        for (DriverExecutionProfile profile : profiles) {
+          map.put(
+              profile.getName(),
+              mockLoadBalancingPolicy(
+                  this,
+                  profile.getName(),
+                  profile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)));
+        }
+        return map.build();
+      }
+
+      @NonNull
+      @Override
+      public ConsistencyLevelRegistry getConsistencyLevelRegistry() {
+        return mock(ConsistencyLevelRegistry.class);
+      }
+    };
+  }
+
+  public static DriverExecutionProfile defaultProfile(String localDc) {
+    return createProfile(DriverExecutionProfile.DEFAULT_NAME, localDc);
+  }
+
+  public static DriverExecutionProfile createProfile(String name, String localDc) {
+    DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class);
+    when(defaultProfile.getName()).thenReturn(name);
+    when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none"))
+        .thenReturn("none");
+    when(defaultProfile.getDuration(DefaultDriverOption.METRICS_NODE_EXPIRE_AFTER))
+        .thenReturn(Duration.ofMinutes(5));
+    when(defaultProfile.isDefined(DefaultDriverOption.METRICS_FACTORY_CLASS)).thenReturn(true);
+    when(defaultProfile.getString(DefaultDriverOption.METRICS_FACTORY_CLASS))
+        .thenReturn("DefaultMetricsFactory");
+    when(defaultProfile.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))
+        .thenReturn(localDc);
+    return defaultProfile;
+  }
+
+  public static void allowRemoteDcConnectivity(
+      DriverExecutionProfile profile,
+      int maxNodesPerRemoteDc,
+      boolean allowRemoteSatisfyLocalDc,
+      List<String> preferredRemoteDcs) {
+    when(profile.getInt(DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_MAX_NODES_PER_REMOTE_DC))
+        .thenReturn(maxNodesPerRemoteDc);
+    when(profile.getBoolean(
+            DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_ALLOW_FOR_LOCAL_CONSISTENCY_LEVELS))
+        .thenReturn(allowRemoteSatisfyLocalDc);
+    when(profile.getStringList(DefaultDriverOption.LOAD_BALANCING_DC_FAILOVER_PREFERRED_REMOTE_DCS))
+        .thenReturn(preferredRemoteDcs);
+  }
+
+  private static LoadBalancingPolicy mockLoadBalancingPolicy(
+      DefaultDriverContext driverContext, String profile, String localDc) {
+    LoadBalancingPolicy loadBalancingPolicy =
+        new DefaultLoadBalancingPolicy(driverContext, profile) {
+          @NonNull
+          @Override
+          protected Optional<String> discoverLocalDc(@NonNull Map<UUID, Node> nodes) {
+            return Optional.ofNullable(localDc);
+          }
+
+          @NonNull
+          @Override
+          protected NodeDistanceEvaluator createNodeDistanceEvaluator(
+              @Nullable String localDc, @NonNull Map<UUID, Node> nodes) {
+            return mock(NodeDistanceEvaluator.class);
+          }
+        };
+    loadBalancingPolicy.init(
+        Collections.emptyMap(), mock(LoadBalancingPolicy.DistanceReporter.class));
+    return loadBalancingPolicy;
   }
 }
diff --git a/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java b/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java
index 33811b2..d12e50b 100644
--- a/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java
+++ b/core/src/test/java/com/datastax/oss/driver/internal/core/context/StartupOptionsBuilderTest.java
@@ -26,10 +26,10 @@
 import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
 import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
 import com.datastax.oss.driver.api.core.session.Session;
+import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
 import com.datastax.oss.protocol.internal.request.Startup;
 import com.tngtech.java.junit.dataprovider.DataProvider;
 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
-import java.util.Optional;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -41,7 +41,8 @@
     DriverExecutionProfile defaultProfile = mock(DriverExecutionProfile.class);
     when(defaultProfile.getString(DefaultDriverOption.PROTOCOL_COMPRESSION, "none"))
         .thenReturn(compression);
-    return MockedDriverContextFactory.defaultDriverContext(Optional.of(defaultProfile));
+    when(defaultProfile.getName()).thenReturn(DriverExecutionProfile.DEFAULT_NAME);
+    return MockedDriverContextFactory.defaultDriverContext(defaultProfile);
   }
 
   private void assertDefaultStartupOptions(Startup startup) {
@@ -94,4 +95,44 @@
               new Startup(ctx.getStartupOptions());
             });
   }
+
+  @Test
+  public void should_include_all_local_dcs_in_startup_message() {
+
+    DefaultDriverContext ctx =
+        MockedDriverContextFactory.defaultDriverContext(
+            MockedDriverContextFactory.defaultProfile("us-west-2"),
+            MockedDriverContextFactory.createProfile("oltp", "us-east-2"),
+            MockedDriverContextFactory.createProfile("olap", "eu-central-1"));
+    Startup startup = new Startup(ctx.getStartupOptions());
+    assertThat(startup.options)
+        .containsEntry(
+            StartupOptionsBuilder.DRIVER_BAGGAGE,
+            "{\"default\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"us-west-2\"}},"
+                + "\"oltp\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"us-east-2\"}},"
+                + "\"olap\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"eu-central-1\"}}}");
+  }
+
+  @Test
+  public void should_include_all_lbp_details_in_startup_message() {
+
+    DriverExecutionProfile defaultProfile = MockedDriverContextFactory.defaultProfile("dc1");
+    DriverExecutionProfile oltpProfile = MockedDriverContextFactory.createProfile("oltp", "dc1");
+    MockedDriverContextFactory.allowRemoteDcConnectivity(
+        oltpProfile, 2, true, ImmutableList.of("dc2", "dc3"));
+    DefaultDriverContext ctx =
+        MockedDriverContextFactory.defaultDriverContext(defaultProfile, oltpProfile);
+
+    Startup startup = new Startup(ctx.getStartupOptions());
+
+    assertThat(startup.options)
+        .containsEntry(
+            StartupOptionsBuilder.DRIVER_BAGGAGE,
+            "{\"default\":{\"DefaultLoadBalancingPolicy\":{\"localDc\":\"dc1\"}},"
+                + "\"oltp\":{\"DefaultLoadBalancingPolicy\":{"
+                + "\"localDc\":\"dc1\","
+                + "\"preferredRemoteDcs\":[\"dc2\",\"dc3\"],"
+                + "\"allowDcFailoverForLocalCl\":true,"
+                + "\"maxNodesPerRemoteDc\":2}}}");
+  }
 }