Support arbitrary network driver options in wslc network create (#40859)

beena352 committed Jul 1, 2026 at 17:16 UTC a22a4c94590ff0ef457f4a7be8a5dec8dd61e3a5
13 files changed +261 -143
localization/strings/en-US/Resources.resw
+13 -2
@@ -2340,8 +2340,8 @@ For privacy information about this product please visit https://aka.ms/privacy.<
2340 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2341 </data>
2342 <data name="MessageWslcGatewayRequiresSubnet" xml:space="preserve">
2343 - <value>Network driver option 'Gateway' requires 'Subnet' to also be specified.</value>
2344 - <comment>{Locked="Gateway"}{Locked="Subnet"}Command line arguments, file names and string inserts should not be translated</comment>
2343 + <value>The '--gateway' option requires '--subnet' to also be specified.</value>
2344 + <comment>{Locked="--gateway'"}{Locked="--subnet'"}Command line arguments, file names and string inserts should not be translated</comment>
2345 </data>
2346 <data name = "MessageWslcNetworkInUse" xml:space = "preserve" >
2347 <value>Network '{}' has active endpoints.</value>
@@ -3115,6 +3115,17 @@ On first run, creates the file with all settings commented out at their defaults
3115 <data name="WSLCCLI_NetworkLabelArgDescription" xml:space="preserve">
3116 <value>Network metadata setting</value>
3117 </data>
3118 + <data name="WSLCCLI_NetworkInternalArgDescription" xml:space="preserve">
3119 + <value>Restrict external access to the network</value>
3120 + </data>
3121 + <data name="WSLCCLI_NetworkSubnetArgDescription" xml:space="preserve">
3122 + <value>Subnet in CIDR format that represents a network segment</value>
3123 + <comment>{Locked="CIDR"}Command line arguments, file names and string inserts should not be translated</comment>
3124 + </data>
3125 + <data name="WSLCCLI_NetworkGatewayArgDescription" xml:space="preserve">
3126 + <value>IPv4 or IPv6 gateway for the subnet</value>
3127 + <comment>{Locked="IPv4"}{Locked="IPv6"}Command line arguments, file names and string inserts should not be translated</comment>
3128 + </data>
3129 <data name="WSLCCLI_NetworkRemoveDesc" xml:space="preserve">
3130 <value>Remove one or more networks.</value>
3131 </data>
src/windows/inc/docker_schema.h
+4 -2
@@ -146,9 +146,10 @@ struct CreateNetwork
146 std::string Driver;
147 bool Internal{};
148 std::optional<IPAM> IPAM;
149 + std::optional<std::map<std::string, std::string>> Options;
150 std::map<std::string, std::string> Labels;
151
151 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateNetwork, Name, Driver, Internal, IPAM, Labels);
152 + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(CreateNetwork, Name, Driver, Internal, IPAM, Options, Labels);
153 };
154
155 struct Network
@@ -159,9 +160,10 @@ struct Network
160 std::string Scope;
161 bool Internal{};
162 IPAM IPAM;
163 + std::optional<std::map<std::string, std::string>> Options;
164 std::map<std::string, std::string> Labels;
165
164 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Network, Id, Name, Driver, Scope, Internal, IPAM, Labels);
166 + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Network, Id, Name, Driver, Scope, Internal, IPAM, Options, Labels);
167 };
168
169 struct ContainerNetworkRequest
src/windows/inc/wslc_schema.h
+2 -1
@@ -195,9 +195,10 @@ struct Network
195 std::string Scope;
196 bool Internal{};
197 IPAM IPAM;
198 + std::optional<std::map<std::string, std::string>> Options;
199 std::map<std::string, std::string> Labels;
200
200 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Network, Id, Name, Driver, Scope, Internal, IPAM, Labels);
201 + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Network, Id, Name, Driver, Scope, Internal, IPAM, Options, Labels);
202 };
203
204 } // namespace wsl::windows::common::wslc_schema
src/windows/service/inc/wslc.idl
+3
@@ -534,6 +534,9 @@ typedef struct _WSLCNetworkOptions
534 ULONG DriverOptsCount;
535 [unique, size_is(LabelsCount)] const WSLCLabel* Labels;
536 ULONG LabelsCount;
537 + BOOL Internal;
538 + [unique] LPCSTR Subnet;
539 + [unique] LPCSTR Gateway;
540 } WSLCNetworkOptions;
541
542 typedef char WSLCNetworkName[WSLC_MAX_NETWORK_NAME_LENGTH + 1];
src/windows/wslc/arguments/ArgumentDefinitions.h
+3
@@ -61,6 +61,7 @@ _(Since, "since", NO_ALIAS, Kind::Value, L
61 _(Until, "until", NO_ALIAS, Kind::Value, Localization::WSLCCLI_UntilArgDescription()) \
62 _(Format, "format", NO_ALIAS, Kind::Value, Localization::WSLCCLI_FormatArgDescription()) \
63 _(ForwardArgs, "arguments", NO_ALIAS, Kind::Forward, Localization::WSLCCLI_ForwardArgsDescription()) \
64 +_(Gateway, "gateway", NO_ALIAS, Kind::Value, Localization::WSLCCLI_NetworkGatewayArgDescription()) \
65 _(Gpus, "gpus", NO_ALIAS, Kind::Value, Localization::WSLCCLI_GpusArgDescription()) \
66 /*_(GroupId, "groupid", NO_ALIAS, Kind::Value, Localization::WSLCCLI_GroupIdArgDescription())*/ \
67 _(Help, "help", WSLC_CLI_HELP_ARG, Kind::Flag, Localization::WSLCCLI_HelpArgDescription()) \
@@ -70,6 +71,7 @@ _(ImageId, "image", NO_ALIAS, Kind::Positional, L
71 _(ImportFile, "file", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_ImportFileArgDescription()) \
72 _(Input, "input", L"i", Kind::Value, Localization::WSLCCLI_InputArgDescription()) \
73 _(Interactive, "interactive", L"i", Kind::Flag, Localization::WSLCCLI_InteractiveArgDescription()) \
74 +_(Internal, "internal", NO_ALIAS, Kind::Flag, Localization::WSLCCLI_NetworkInternalArgDescription()) \
75 _(Label, "label", L"l", Kind::Value, Localization::WSLCCLI_LabelArgDescription()) \
76 _(Last, "last", L"n", Kind::Value, Localization::WSLCCLI_LastArgDescription()) \
77 _(Latest, "latest", L"l", Kind::Flag, Localization::WSLCCLI_LatestArgDescription()) \
@@ -104,6 +106,7 @@ _(Signal, "signal", L"s", Kind::Value, L
106 _(Source, "source", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_SourceArgDescription()) \
107 _(StopSignal, "stop-signal", NO_ALIAS, Kind::Value, Localization::WSLCCLI_StopSignalArgDescription()) \
108 _(StopTimeout, "stop-timeout", NO_ALIAS, Kind::Value, Localization::WSLCCLI_StopTimeoutArgDescription()) \
109 +_(Subnet, "subnet", NO_ALIAS, Kind::Value, Localization::WSLCCLI_NetworkSubnetArgDescription()) \
110 _(Tail, "tail", L"n", Kind::Value, Localization::WSLCCLI_TailArgDescription()) \
111 _(Tag, "tag", L"t", Kind::Value, Localization::WSLCCLI_TagArgDescription()) \
112 _(Target, "target", NO_ALIAS, Kind::Positional, Localization::WSLCCLI_TargetArgDescription()) \
src/windows/wslc/commands/NetworkCreateCommand.cpp
+3
@@ -31,6 +31,9 @@ std::vector<Argument> NetworkCreateCommand::GetArguments() const
31 Argument::Create(ArgType::Driver, std::nullopt, std::nullopt, Localization::WSLCCLI_NetworkDriverOptionDescription()),
32 Argument::Create(ArgType::Options, false, NO_LIMIT),
33 Argument::Create(ArgType::Label, false, NO_LIMIT, Localization::WSLCCLI_NetworkLabelArgDescription()),
34 + Argument::Create(ArgType::Gateway),
35 + Argument::Create(ArgType::Internal),
36 + Argument::Create(ArgType::Subnet),
37 };
38 }
39
src/windows/wslc/services/NetworkModel.h
+3
@@ -25,6 +25,9 @@ struct CreateNetworkOptions
25 std::optional<std::string> Driver;
26 std::vector<std::pair<std::string, std::string>> DriverOpts{};
27 std::vector<std::pair<std::string, std::string>> Labels{};
28 + bool Internal{false};
29 + std::optional<std::string> Subnet;
30 + std::optional<std::string> Gateway;
31 };
32
33 struct PruneNetworksResult
src/windows/wslc/services/NetworkService.cpp
+11
@@ -50,6 +50,17 @@ void NetworkService::Create(models::Session& session, const models::CreateNetwor
50 options.Labels = labels.data();
51 options.LabelsCount = static_cast<ULONG>(labels.size());
52
53 + options.Internal = createOptions.Internal ? TRUE : FALSE;
54 + if (createOptions.Subnet.has_value())
55 + {
56 + options.Subnet = createOptions.Subnet->c_str();
57 + }
58 +
59 + if (createOptions.Gateway.has_value())
60 + {
61 + options.Gateway = createOptions.Gateway->c_str();
62 + }
63 +
64 auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
65 THROW_IF_FAILED(session.Get()->CreateNetwork(&options, warningCallback.Get()));
66 }
src/windows/wslc/tasks/NetworkTasks.cpp
+12
@@ -95,6 +95,18 @@ void CreateNetwork(CLIExecutionContext& context)
95 options.Driver = WideToMultiByte(context.Args.Get<ArgType::Driver>());
96 }
97
98 + options.Internal = context.Args.Contains(ArgType::Internal);
99 +
100 + if (context.Args.Contains(ArgType::Subnet))
101 + {
102 + options.Subnet = WideToMultiByte(context.Args.Get<ArgType::Subnet>());
103 + }
104 +
105 + if (context.Args.Contains(ArgType::Gateway))
106 + {
107 + options.Gateway = WideToMultiByte(context.Args.Get<ArgType::Gateway>());
108 + }
109 +
110 NetworkService::Create(context.Data.Get<Data::Session>(), options);
111 PrintMessage(MultiByteToWide(options.Name));
112 }
src/windows/wslcsession/WSLCNetworkMetadata.h
+1
@@ -45,6 +45,7 @@ struct NetworkEntry
45 std::string Scope;
46 bool Internal{false};
47 std::map<std::string, std::string> Labels;
48 + std::map<std::string, std::string> Options;
49 NetworkIPAM IPAM;
50 };
51
src/windows/wslcsession/WSLCSession.cpp
+26 -21
@@ -2443,7 +2443,7 @@ try
2443 RETURN_HR_IF_NULL(E_POINTER, Options->Name);
2444
2445 std::string name = Options->Name;
2446 - std::string driver = (Options->Driver != nullptr) ? Options->Driver : WSLCBridgeNetworkDriver;
2446 + std::string driver = Options->Driver != nullptr ? Options->Driver : WSLCBridgeNetworkDriver;
2447
2448 ValidateName(name.c_str(), WSLC_MAX_NETWORK_NAME_LENGTH);
2449
@@ -2453,17 +2453,6 @@ try
2453 auto driverOpts = wslutil::ParseKeyValuePairs(Options->DriverOpts, Options->DriverOptsCount);
2454 auto labels = wslutil::ParseKeyValuePairs(Options->Labels, Options->LabelsCount, WSLCNetworkManagedLabel);
2455
2456 - static constexpr std::array<std::string_view, 3> c_supportedDriverOpts{"Internal", "Subnet", "Gateway"};
2457 - for (const auto& [key, _] : driverOpts)
2458 - {
2459 - const bool supported = std::any_of(
2460 - c_supportedDriverOpts.begin(), c_supportedDriverOpts.end(), [&](std::string_view opt) { return key == opt; });
2461 - THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcInvalidNetworkDriverOption(key), !supported);
2462 - }
2463 -
2464 - THROW_HR_WITH_USER_ERROR_IF(
2465 - E_INVALIDARG, Localization::MessageWslcGatewayRequiresSubnet(), driverOpts.contains("Gateway") && !driverOpts.contains("Subnet"));
2466 -
2456 auto lock = m_lock.lock_shared();
2457 THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_dockerClient);
2458 THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), !m_virtualMachine);
@@ -2477,20 +2466,19 @@ try
2466 request.Labels = labels;
2467 request.Labels[WSLCNetworkManagedLabel] = "true";
2468
2480 - if (auto it = driverOpts.find("Internal"); it != driverOpts.end())
2481 - {
2482 - request.Internal = (it->second == "true");
2483 - }
2469 + request.Internal = static_cast<bool>(Options->Internal);
2470 +
2471 + THROW_HR_WITH_USER_ERROR_IF(
2472 + E_INVALIDARG, Localization::MessageWslcGatewayRequiresSubnet(), Options->Gateway != nullptr && Options->Subnet == nullptr);
2473
2485 - if (auto it = driverOpts.find("Subnet"); it != driverOpts.end())
2474 + if (Options->Subnet != nullptr)
2475 {
2476 docker_schema::IPAMConfig ipamConfig;
2488 - ipamConfig.Subnet = it->second;
2477 + ipamConfig.Subnet = Options->Subnet;
2478
2490 - auto gatewayIt = driverOpts.find("Gateway");
2491 - if (gatewayIt != driverOpts.end())
2479 + if (Options->Gateway != nullptr)
2480 {
2493 - ipamConfig.Gateway = gatewayIt->second;
2481 + ipamConfig.Gateway = Options->Gateway;
2482 }
2483
2484 auto& ipam = request.IPAM.emplace();
@@ -2498,6 +2486,11 @@ try
2486 ipam.Config.emplace().push_back(std::move(ipamConfig));
2487 }
2488
2489 + if (!driverOpts.empty())
2490 + {
2491 + request.Options = std::move(driverOpts);
2492 + }
2493 +
2494 docker_schema::CreateNetworkResponse createResult;
2495 try
2496 {
@@ -2535,6 +2528,10 @@ try
2528 entry.Scope = full.Scope;
2529 entry.Internal = full.Internal;
2530 entry.Labels = full.Labels;
2531 + if (full.Options)
2532 + {
2533 + entry.Options = *full.Options;
2534 + }
2535 entry.IPAM.Driver = full.IPAM.Driver;
2536 if (full.IPAM.Config)
2537 {
@@ -2659,6 +2656,10 @@ try
2656 result.Scope = entry.Scope;
2657 result.Internal = entry.Internal;
2658 result.Labels = entry.Labels;
2659 + if (!entry.Options.empty())
2660 + {
2661 + result.Options = entry.Options;
2662 + }
2663
2664 result.IPAM.Driver = entry.IPAM.Driver;
2665 if (entry.IPAM.Config)
@@ -3489,6 +3490,10 @@ void WSLCSession::RecoverExistingNetworks()
3490 entry.Scope = network.Scope;
3491 entry.Internal = network.Internal;
3492 entry.Labels = network.Labels;
3493 + if (network.Options)
3494 + {
3495 + entry.Options = *network.Options;
3496 + }
3497 entry.IPAM.Driver = network.IPAM.Driver;
3498 if (network.IPAM.Config)
3499 {
test/windows/WSLCTests.cpp
+102 -112
@@ -5166,25 +5166,27 @@ class WSLCTests
5166 WSLC_TEST_METHOD(NetworkCreateWithSubnetTest)
5167 {
5168 const std::string networkName = "subnet-test-net";
5169 + const std::string subnet = "172.28.0.0/16";
5170
5171 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5172
5172 - WSLCDriverOption subnetOpt[] = {{"Subnet", "172.28.0.0/16"}};
5173 -
5173 WSLCNetworkOptions options{};
5174 options.Name = networkName.c_str();
5175 options.Driver = "bridge";
5177 - options.DriverOpts = subnetOpt;
5178 - options.DriverOptsCount = ARRAYSIZE(subnetOpt);
5176 + options.Subnet = subnet.c_str();
5177
5178 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5179
5180 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&options, nullptr));
5181
5184 - wil::unique_cotaskmem_array_ptr<WSLCNetworkInformation> networks;
5185 - VERIFY_SUCCEEDED(m_defaultSession->ListNetworks(networks.addressof(), networks.size_address<ULONG>()));
5186 - VERIFY_ARE_EQUAL(1u, networks.size());
5187 - VERIFY_ARE_EQUAL(networkName, std::string(networks[0].Name));
5182 + wil::unique_cotaskmem_ansistring output;
5183 + VERIFY_SUCCEEDED(m_defaultSession->InspectNetwork(networkName.c_str(), &output));
5184 + VERIFY_IS_NOT_NULL(output.get());
5185 +
5186 + auto inspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::Network>(output.get());
5187 + VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
5188 + VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
5189 + VERIFY_ARE_EQUAL(subnet, inspect.IPAM.Config->at(0).Subnet);
5190 }
5191
5192 WSLC_TEST_METHOD(NetworkCreateInternalTest)
@@ -5193,22 +5195,22 @@ class WSLCTests
5195
5196 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5197
5196 - WSLCDriverOption internalOpt[] = {{"Internal", "true"}};
5197 -
5198 WSLCNetworkOptions options{};
5199 options.Name = networkName.c_str();
5200 options.Driver = "bridge";
5201 - options.DriverOpts = internalOpt;
5202 - options.DriverOptsCount = ARRAYSIZE(internalOpt);
5201 + options.Internal = TRUE;
5202
5203 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5204
5205 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&options, nullptr));
5206
5208 - wil::unique_cotaskmem_array_ptr<WSLCNetworkInformation> networks;
5209 - VERIFY_SUCCEEDED(m_defaultSession->ListNetworks(networks.addressof(), networks.size_address<ULONG>()));
5210 - VERIFY_ARE_EQUAL(1u, networks.size());
5211 - VERIFY_ARE_EQUAL(networkName, std::string(networks[0].Name));
5207 + wil::unique_cotaskmem_ansistring output;
5208 + VERIFY_SUCCEEDED(m_defaultSession->InspectNetwork(networkName.c_str(), &output));
5209 + VERIFY_IS_NOT_NULL(output.get());
5210 +
5211 + auto inspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::Network>(output.get());
5212 + VERIFY_ARE_EQUAL(networkName, inspect.Name);
5213 + VERIFY_IS_TRUE(inspect.Internal);
5214 }
5215
5216 WSLC_TEST_METHOD(NetworkCreateWithLabelsTest)
@@ -5242,11 +5244,14 @@ class WSLCTests
5244
5245 WSLC_TEST_METHOD(NetworkCreateInvalidDriverAndOptionTest)
5246 {
5247 + const std::string networkName = "bad-network-create-input";
5248 +
5249 + LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5250 + auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5251 +
5252 WSLCNetworkOptions options{};
5246 - options.Name = "bad-network-create-input";
5253 + options.Name = networkName.c_str();
5254 options.Driver = "bridge";
5248 - options.DriverOpts = nullptr;
5249 - options.DriverOptsCount = 0;
5255
5256 auto verifyInvalid = [&](PCWSTR expectedMessage) {
5257 VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateNetwork(&options, nullptr));
@@ -5254,35 +5259,18 @@ class WSLCTests
5259 };
5260
5261 // Invalid drivers (unknown, wrong case, empty)
5262 + for (const char* driver : {"overlay", "Bridge", ""})
5263 {
5258 - options.DriverOpts = nullptr;
5259 - options.DriverOptsCount = 0;
5260 - for (const char* driver : {"overlay", "Bridge", ""})
5261 - {
5262 - options.Driver = driver;
5263 - verifyInvalid(L"Unsupported network driver:");
5264 - }
5265 - }
5266 -
5267 - // Invalid driver options (wrong case and unknown keys)
5268 - {
5269 - options.Driver = "bridge";
5270 - for (const char* key : {"internal", "subnet", "gateway", "foo"})
5271 - {
5272 - WSLCDriverOption opt{key, "true"};
5273 - options.DriverOpts = &opt;
5274 - options.DriverOptsCount = 1;
5275 - verifyInvalid(wsl::shared::string::MultiByteToWide(key).c_str());
5276 - }
5264 + options.Driver = driver;
5265 + verifyInvalid(L"Unsupported network driver:");
5266 }
5267
5268 // Gateway specified without Subnet
5269 {
5270 options.Driver = "bridge";
5282 - WSLCDriverOption opt{"Gateway", "172.44.0.1"};
5283 - options.DriverOpts = &opt;
5284 - options.DriverOptsCount = 1;
5285 - verifyInvalid(L"requires 'Subnet'");
5271 + options.Subnet = nullptr;
5272 + options.Gateway = "172.44.0.1";
5273 + verifyInvalid(L"--subnet");
5274 }
5275 }
5276
@@ -5346,14 +5334,12 @@ class WSLCTests
5334 const std::string networkName = "bad-subnet-net";
5335
5336 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5349 -
5350 - WSLCDriverOption opts[] = {{"Subnet", "not-a-cidr"}};
5337 + auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5338
5339 WSLCNetworkOptions options{};
5340 options.Name = networkName.c_str();
5341 options.Driver = "bridge";
5355 - options.DriverOpts = opts;
5356 - options.DriverOptsCount = ARRAYSIZE(opts);
5342 + options.Subnet = "not-a-cidr";
5343
5344 VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateNetwork(&options, nullptr));
5345 ValidateCOMErrorMessageContains(L"invalid subnet");
@@ -5367,14 +5353,13 @@ class WSLCTests
5353 const std::string networkName = "bad-gateway-net";
5354
5355 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5370 -
5371 - WSLCDriverOption opts[] = {{"Subnet", "172.27.0.0/16"}, {"Gateway", "999.999.999.999"}};
5356 + auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5357
5358 WSLCNetworkOptions options{};
5359 options.Name = networkName.c_str();
5360 options.Driver = "bridge";
5376 - options.DriverOpts = opts;
5377 - options.DriverOptsCount = ARRAYSIZE(opts);
5361 + options.Subnet = "172.27.0.0/16";
5362 + options.Gateway = "999.999.999.999";
5363
5364 VERIFY_ARE_EQUAL(E_INVALIDARG, m_defaultSession->CreateNetwork(&options, nullptr));
5365 ValidateCOMErrorMessageContains(L"invalid gateway");
@@ -5386,10 +5371,39 @@ class WSLCTests
5371 WSLC_TEST_METHOD(NetworkCreateWithGatewayTest)
5372 {
5373 const std::string networkName = "gateway-test-net";
5374 + const std::string subnet = "172.31.0.0/16";
5375 + const std::string gateway = "172.31.0.1";
5376
5377 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5378
5392 - WSLCDriverOption opts[] = {{"Subnet", "172.31.0.0/16"}, {"Gateway", "172.31.0.1"}};
5379 + WSLCNetworkOptions options{};
5380 + options.Name = networkName.c_str();
5381 + options.Driver = "bridge";
5382 + options.Subnet = subnet.c_str();
5383 + options.Gateway = gateway.c_str();
5384 +
5385 + auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5386 +
5387 + VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&options, nullptr));
5388 +
5389 + wil::unique_cotaskmem_ansistring output;
5390 + VERIFY_SUCCEEDED(m_defaultSession->InspectNetwork(networkName.c_str(), &output));
5391 + VERIFY_IS_NOT_NULL(output.get());
5392 +
5393 + auto inspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::Network>(output.get());
5394 + VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
5395 + VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
5396 + VERIFY_ARE_EQUAL(subnet, inspect.IPAM.Config->at(0).Subnet);
5397 + VERIFY_ARE_EQUAL(gateway, inspect.IPAM.Config->at(0).Gateway);
5398 + }
5399 +
5400 + WSLC_TEST_METHOD(NetworkCreateWithArbitraryDriverOptsTest)
5401 + {
5402 + const std::string networkName = "arbitrary-opts-test-net";
5403 +
5404 + LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5405 +
5406 + WSLCDriverOption opts[] = {{"my.abc.key", "mygod"}, {"com.example.flag", "1"}};
5407
5408 WSLCNetworkOptions options{};
5409 options.Name = networkName.c_str();
@@ -5406,10 +5420,11 @@ class WSLCTests
5420 VERIFY_IS_NOT_NULL(output.get());
5421
5422 auto inspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::Network>(output.get());
5409 - VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
5410 - VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
5411 - VERIFY_ARE_EQUAL(std::string("172.31.0.0/16"), inspect.IPAM.Config->at(0).Subnet);
5412 - VERIFY_ARE_EQUAL(std::string("172.31.0.1"), inspect.IPAM.Config->at(0).Gateway);
5423 + VERIFY_IS_TRUE(inspect.Options.has_value());
5424 + VERIFY_IS_TRUE(inspect.Options->contains("my.abc.key"));
5425 + VERIFY_IS_TRUE(inspect.Options->contains("com.example.flag"));
5426 + VERIFY_ARE_EQUAL(std::string("mygod"), inspect.Options->at("my.abc.key"));
5427 + VERIFY_ARE_EQUAL(std::string("1"), inspect.Options->at("com.example.flag"));
5428 }
5429
5430 WSLC_TEST_METHOD(NetworkSessionRecoveryTest)
@@ -5418,11 +5433,13 @@ class WSLCTests
5433
5434 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5435
5436 + WSLCDriverOption recoveryOpts[] = {{"recovery.test.key", "preserved"}};
5437 +
5438 WSLCNetworkOptions options{};
5439 options.Name = networkName.c_str();
5440 options.Driver = "bridge";
5424 - options.DriverOpts = nullptr;
5425 - options.DriverOptsCount = 0;
5441 + options.DriverOpts = recoveryOpts;
5442 + options.DriverOptsCount = ARRAYSIZE(recoveryOpts);
5443 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&options, nullptr));
5444
5445 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
@@ -5436,6 +5453,16 @@ class WSLCTests
5453 VERIFY_ARE_EQUAL(networkName, std::string(networks[0].Name));
5454 VERIFY_ARE_EQUAL(std::string("bridge"), std::string(networks[0].Driver));
5455 VERIFY_IS_TRUE(strlen(networks[0].Id) > 0);
5456 +
5457 + // Verify arbitrary driver options survive session recovery.
5458 + wil::unique_cotaskmem_ansistring output;
5459 + VERIFY_SUCCEEDED(m_defaultSession->InspectNetwork(networkName.c_str(), &output));
5460 + VERIFY_IS_NOT_NULL(output.get());
5461 +
5462 + auto inspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::Network>(output.get());
5463 + VERIFY_IS_TRUE(inspect.Options.has_value());
5464 + VERIFY_IS_TRUE(inspect.Options->contains("recovery.test.key"));
5465 + VERIFY_ARE_EQUAL(std::string("preserved"), inspect.Options->at("recovery.test.key"));
5466 }
5467
5468 WSLC_TEST_METHOD(NetworkMultipleCreateListDeleteTest)
@@ -5461,20 +5488,16 @@ class WSLCTests
5488 optionsA.DriverOptsCount = 0;
5489 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&optionsA, nullptr));
5490
5464 - WSLCDriverOption subnetOpt[] = {{"Subnet", "172.29.0.0/16"}};
5491 WSLCNetworkOptions optionsB{};
5492 optionsB.Name = networkNameB.c_str();
5493 optionsB.Driver = "bridge";
5468 - optionsB.DriverOpts = subnetOpt;
5469 - optionsB.DriverOptsCount = ARRAYSIZE(subnetOpt);
5494 + optionsB.Subnet = "172.29.0.0/16";
5495 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&optionsB, nullptr));
5496
5472 - WSLCDriverOption internalOpt[] = {{"Internal", "true"}};
5497 WSLCNetworkOptions optionsC{};
5498 optionsC.Name = networkNameC.c_str();
5499 optionsC.Driver = "bridge";
5476 - optionsC.DriverOpts = internalOpt;
5477 - optionsC.DriverOptsCount = ARRAYSIZE(internalOpt);
5500 + optionsC.Internal = TRUE;
5501 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&optionsC, nullptr));
5502
5503 wil::unique_cotaskmem_array_ptr<WSLCNetworkInformation> networks;
@@ -5515,18 +5538,16 @@ class WSLCTests
5538 WSLC_TEST_METHOD(NetworkInspectWithSubnetTest)
5539 {
5540 const std::string networkName = "test-inspect-subnet-net";
5541 + const std::string subnet = "172.30.0.0/16";
5542
5543 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
5544
5545 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
5546
5523 - WSLCDriverOption subnetOpt[] = {{"Subnet", "172.30.0.0/16"}};
5524 -
5547 WSLCNetworkOptions options{};
5548 options.Name = networkName.c_str();
5549 options.Driver = "bridge";
5528 - options.DriverOpts = subnetOpt;
5529 - options.DriverOptsCount = ARRAYSIZE(subnetOpt);
5550 + options.Subnet = subnet.c_str();
5551 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&options, nullptr));
5552
5553 wil::unique_cotaskmem_ansistring output;
@@ -5538,7 +5559,7 @@ class WSLCTests
5559 VERIFY_ARE_EQUAL(inspect.Driver, std::string("bridge"));
5560 VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
5561 VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
5541 - VERIFY_ARE_EQUAL(std::string("172.30.0.0/16"), inspect.IPAM.Config->at(0).Subnet);
5562 + VERIFY_ARE_EQUAL(subnet, inspect.IPAM.Config->at(0).Subnet);
5563 }
5564
5565 WSLC_TEST_METHOD(NetworkInspectNotFoundTest)
@@ -6693,13 +6714,10 @@ class WSLCTests
6714
6715 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6716
6696 - WSLCDriverOption opts[] = {{"Subnet", "172.35.0.0/16"}};
6697 -
6717 WSLCNetworkOptions networkOptions{};
6718 networkOptions.Name = networkName.c_str();
6719 networkOptions.Driver = "bridge";
6701 - networkOptions.DriverOpts = opts;
6702 - networkOptions.DriverOptsCount = ARRAYSIZE(opts);
6720 + networkOptions.Subnet = "172.35.0.0/16";
6721
6722 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions, nullptr));
6723
@@ -6794,13 +6812,10 @@ class WSLCTests
6812
6813 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6814
6797 - WSLCDriverOption opts[] = {{"Subnet", "172.36.0.0/16"}};
6798 -
6815 WSLCNetworkOptions networkOptions{};
6816 networkOptions.Name = networkName.c_str();
6817 networkOptions.Driver = "bridge";
6802 - networkOptions.DriverOpts = opts;
6803 - networkOptions.DriverOptsCount = ARRAYSIZE(opts);
6818 + networkOptions.Subnet = "172.36.0.0/16";
6819
6820 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions, nullptr));
6821
@@ -6825,13 +6840,10 @@ class WSLCTests
6840
6841 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6842
6828 - WSLCDriverOption opts[] = {{"Subnet", "172.37.0.0/16"}};
6829 -
6843 WSLCNetworkOptions networkOptions{};
6844 networkOptions.Name = networkName.c_str();
6845 networkOptions.Driver = "bridge";
6833 - networkOptions.DriverOpts = opts;
6834 - networkOptions.DriverOptsCount = ARRAYSIZE(opts);
6846 + networkOptions.Subnet = "172.37.0.0/16";
6847
6848 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions, nullptr));
6849
@@ -6851,13 +6863,10 @@ class WSLCTests
6863
6864 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6865
6854 - WSLCDriverOption opts[] = {{"Subnet", "172.38.0.0/16"}};
6855 -
6866 WSLCNetworkOptions networkOptions{};
6867 networkOptions.Name = networkName.c_str();
6868 networkOptions.Driver = "bridge";
6859 - networkOptions.DriverOpts = opts;
6860 - networkOptions.DriverOptsCount = ARRAYSIZE(opts);
6869 + networkOptions.Subnet = "172.38.0.0/16";
6870
6871 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions, nullptr));
6872
@@ -6881,13 +6890,10 @@ class WSLCTests
6890
6891 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6892
6884 - WSLCDriverOption opts[] = {{"Subnet", "172.39.0.0/16"}};
6885 -
6893 WSLCNetworkOptions networkOptions{};
6894 networkOptions.Name = networkName.c_str();
6895 networkOptions.Driver = "bridge";
6889 - networkOptions.DriverOpts = opts;
6890 - networkOptions.DriverOptsCount = ARRAYSIZE(opts);
6896 + networkOptions.Subnet = "172.39.0.0/16";
6897
6898 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions, nullptr));
6899
@@ -6922,21 +6928,17 @@ class WSLCTests
6928 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str()));
6929 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str()));
6930
6925 - WSLCDriverOption primaryOpts[] = {{"Subnet", "172.40.0.0/16"}};
6931 WSLCNetworkOptions primaryNetOpts{};
6932 primaryNetOpts.Name = primaryNetwork.c_str();
6933 primaryNetOpts.Driver = "bridge";
6929 - primaryNetOpts.DriverOpts = primaryOpts;
6930 - primaryNetOpts.DriverOptsCount = ARRAYSIZE(primaryOpts);
6934 + primaryNetOpts.Subnet = "172.40.0.0/16";
6935 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&primaryNetOpts, nullptr));
6936 auto primaryCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
6937
6934 - WSLCDriverOption additionalOpts[] = {{"Subnet", "172.41.0.0/16"}};
6938 WSLCNetworkOptions additionalNetOpts{};
6939 additionalNetOpts.Name = additionalNetwork.c_str();
6940 additionalNetOpts.Driver = "bridge";
6938 - additionalNetOpts.DriverOpts = additionalOpts;
6939 - additionalNetOpts.DriverOptsCount = ARRAYSIZE(additionalOpts);
6941 + additionalNetOpts.Subnet = "172.41.0.0/16";
6942 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&additionalNetOpts, nullptr));
6943 auto additionalCleanup =
6944 wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str())); });
@@ -6961,12 +6963,10 @@ class WSLCTests
6963
6964 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str()));
6965
6964 - WSLCDriverOption opts[] = {{"Subnet", "172.48.0.0/16"}};
6966 WSLCNetworkOptions netOpts{};
6967 netOpts.Name = primaryNetwork.c_str();
6968 netOpts.Driver = "bridge";
6968 - netOpts.DriverOpts = opts;
6969 - netOpts.DriverOptsCount = ARRAYSIZE(opts);
6969 + netOpts.Subnet = "172.48.0.0/16";
6970 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts, nullptr));
6971 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
6972
@@ -6987,12 +6987,10 @@ class WSLCTests
6987 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str()));
6988 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(missingNetwork.c_str()));
6989
6990 - WSLCDriverOption opts[] = {{"Subnet", "172.49.0.0/16"}};
6990 WSLCNetworkOptions netOpts{};
6991 netOpts.Name = primaryNetwork.c_str();
6992 netOpts.Driver = "bridge";
6994 - netOpts.DriverOpts = opts;
6995 - netOpts.DriverOptsCount = ARRAYSIZE(opts);
6993 + netOpts.Subnet = "172.49.0.0/16";
6994 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts, nullptr));
6995 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
6996
@@ -7061,21 +7059,17 @@ class WSLCTests
7059 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str()));
7060 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str()));
7061
7064 - WSLCDriverOption primaryOpts[] = {{"Subnet", "172.50.0.0/16"}};
7062 WSLCNetworkOptions primaryNetOpts{};
7063 primaryNetOpts.Name = primaryNetwork.c_str();
7064 primaryNetOpts.Driver = "bridge";
7068 - primaryNetOpts.DriverOpts = primaryOpts;
7069 - primaryNetOpts.DriverOptsCount = ARRAYSIZE(primaryOpts);
7065 + primaryNetOpts.Subnet = "172.50.0.0/16";
7066 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&primaryNetOpts, nullptr));
7067 auto primaryCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
7068
7073 - WSLCDriverOption additionalOpts[] = {{"Subnet", "172.51.0.0/16"}};
7069 WSLCNetworkOptions additionalNetOpts{};
7070 additionalNetOpts.Name = additionalNetwork.c_str();
7071 additionalNetOpts.Driver = "bridge";
7077 - additionalNetOpts.DriverOpts = additionalOpts;
7078 - additionalNetOpts.DriverOptsCount = ARRAYSIZE(additionalOpts);
7072 + additionalNetOpts.Subnet = "172.51.0.0/16";
7073 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&additionalNetOpts, nullptr));
7074 auto additionalCleanup =
7075 wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str())); });
@@ -7098,12 +7092,10 @@ class WSLCTests
7092
7093 auto createNetwork = [&](const std::string& name, const char* subnet) {
7094 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(name.c_str()));
7101 - WSLCDriverOption opts[] = {{"Subnet", subnet}};
7095 WSLCNetworkOptions netOpts{};
7096 netOpts.Name = name.c_str();
7097 netOpts.Driver = "bridge";
7105 - netOpts.DriverOpts = opts;
7106 - netOpts.DriverOptsCount = ARRAYSIZE(opts);
7098 + netOpts.Subnet = subnet;
7099 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts, nullptr));
7100 };
7101
@@ -7229,12 +7221,10 @@ class WSLCTests
7221 {
7222 auto createNetwork = [&](const std::string& name, const char* subnet) {
7223 LOG_IF_FAILED(m_defaultSession->DeleteNetwork(name.c_str()));
7232 - WSLCDriverOption opts[] = {{"Subnet", subnet}};
7224 WSLCNetworkOptions netOpts{};
7225 netOpts.Name = name.c_str();
7226 netOpts.Driver = "bridge";
7236 - netOpts.DriverOpts = opts;
7237 - netOpts.DriverOptsCount = ARRAYSIZE(opts);
7227 + netOpts.Subnet = subnet;
7228 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts, nullptr));
7229 };
7230
test/windows/wslc/e2e/WSLCE2ENetworkCreateTests.cpp
+78 -5
@@ -109,6 +109,76 @@ class WSLCE2ENetworkCreateTests
109 {.Stdout = L"", .Stderr = L"Cannot create a file when that file already exists. \r\nError code: ERROR_ALREADY_EXISTS\r\n", .ExitCode = 1});
110 }
111
112 + WSLC_TEST_METHOD(WSLCE2E_Network_Create_Internal_Success)
113 + {
114 + auto result = RunWslc(std::format(L"network create --internal {}", TestNetworkName));
115 + result.Verify({.Stderr = L"", .ExitCode = 0});
116 + VERIFY_ARE_EQUAL(TestNetworkName, result.GetStdoutOneLine());
117 +
118 + VerifyNetworkIsListed(TestNetworkName);
119 + auto inspect = InspectNetwork(TestNetworkName);
120 + VERIFY_ARE_EQUAL("bridge", inspect.Driver);
121 + VERIFY_IS_TRUE(inspect.Internal);
122 + }
123 +
124 + WSLC_TEST_METHOD(WSLCE2E_Network_Create_Subnet_Success)
125 + {
126 + const std::wstring subnet = L"172.45.0.0/16";
127 + auto result = RunWslc(std::format(L"network create --subnet {} {}", subnet, TestNetworkName));
128 + result.Verify({.Stderr = L"", .ExitCode = 0});
129 + VERIFY_ARE_EQUAL(TestNetworkName, result.GetStdoutOneLine());
130 +
131 + VerifyNetworkIsListed(TestNetworkName);
132 + auto inspect = InspectNetwork(TestNetworkName);
133 + VERIFY_ARE_EQUAL("bridge", inspect.Driver);
134 + VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
135 + VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
136 + VERIFY_ARE_EQUAL(wsl::shared::string::WideToMultiByte(subnet), (*inspect.IPAM.Config)[0].Subnet);
137 + }
138 +
139 + WSLC_TEST_METHOD(WSLCE2E_Network_Create_SubnetAndGateway_Success)
140 + {
141 + const std::wstring subnet = L"172.46.0.0/16";
142 + const std::wstring gateway = L"172.46.0.1";
143 + auto result = RunWslc(std::format(L"network create --subnet {} --gateway {} {}", subnet, gateway, TestNetworkName));
144 + result.Verify({.Stderr = L"", .ExitCode = 0});
145 + VERIFY_ARE_EQUAL(TestNetworkName, result.GetStdoutOneLine());
146 +
147 + VerifyNetworkIsListed(TestNetworkName);
148 + auto inspect = InspectNetwork(TestNetworkName);
149 + VERIFY_ARE_EQUAL("bridge", inspect.Driver);
150 + VERIFY_IS_TRUE(inspect.IPAM.Config.has_value());
151 + VERIFY_ARE_EQUAL(1u, inspect.IPAM.Config->size());
152 + VERIFY_ARE_EQUAL(wsl::shared::string::WideToMultiByte(subnet), (*inspect.IPAM.Config)[0].Subnet);
153 + VERIFY_ARE_EQUAL(wsl::shared::string::WideToMultiByte(gateway), (*inspect.IPAM.Config)[0].Gateway);
154 + }
155 +
156 + WSLC_TEST_METHOD(WSLCE2E_Network_Create_GatewayWithoutSubnet_Fail)
157 + {
158 + auto result = RunWslc(std::format(L"network create --gateway 172.47.0.1 {}", TestNetworkName));
159 + result.Verify(
160 + {.Stdout = L"",
161 + .Stderr = L"The '--gateway' option requires '--subnet' to also be specified.\r\nError code: E_INVALIDARG\r\n",
162 + .ExitCode = 1});
163 +
164 + VerifyNetworkIsNotListed(TestNetworkName);
165 + }
166 +
167 + WSLC_TEST_METHOD(WSLCE2E_Network_Create_WithOpt_Success)
168 + {
169 + constexpr auto c_opts = L"--opt com.docker.network.bridge.enable_icc=true --opt com.docker.network.driver.mtu=1450";
170 + auto result = RunWslc(std::format(L"network create {} {}", c_opts, TestNetworkName));
171 + result.Verify({.Stderr = L"", .ExitCode = 0});
172 + VERIFY_ARE_EQUAL(TestNetworkName, result.GetStdoutOneLine());
173 +
174 + VerifyNetworkIsListed(TestNetworkName);
175 + auto inspect = InspectNetwork(TestNetworkName);
176 + VERIFY_ARE_EQUAL("bridge", inspect.Driver);
177 + VERIFY_IS_TRUE(inspect.Options.has_value());
178 + VERIFY_ARE_EQUAL("true", (*inspect.Options)["com.docker.network.bridge.enable_icc"]);
179 + VERIFY_ARE_EQUAL("1450", (*inspect.Options)["com.docker.network.driver.mtu"]);
180 + }
181 +
182 private:
183 const std::wstring TestNetworkName = L"wslc-e2e-network-create";
184
@@ -145,11 +215,14 @@ private:
215 std::wstring GetAvailableOptions() const
216 {
217 std::wstringstream options;
148 - options << L"The following options are available:\r\n" //
149 - << L" -d,--driver Specify network driver name (default: bridge)\r\n" //
150 - << L" -o,--opt Set driver specific options\r\n" //
151 - << L" -l,--label Network metadata setting\r\n" //
152 - << L" -?,--help Shows help about the selected command\r\n" //
218 + options << L"The following options are available:\r\n" //
219 + << L" -d,--driver Specify network driver name (default: bridge)\r\n" //
220 + << L" -o,--opt Set driver specific options\r\n" //
221 + << L" -l,--label Network metadata setting\r\n" //
222 + << L" --gateway IPv4 or IPv6 gateway for the subnet\r\n" //
223 + << L" --internal Restrict external access to the network\r\n" //
224 + << L" --subnet Subnet in CIDR format that represents a network segment\r\n" //
225 + << L" -?,--help Shows help about the selected command\r\n" //
226 << L"\r\n";
227 return options.str();
228 }