Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
Execute ifconfig commands to set up tap/vmnet devices
Browse files Browse the repository at this point in the history
This execute various ifconfig commands prior to running a virtual
machine. Firstly, the tap/vmnet device is created with "ifconfig
create".  This step is allowed to fail; the device may already
exists. Secondly, the MAC address of the device is configured. This
step is not allowed to fail; if it fails, the device probably does
not exist. Lastly, the device is added to all of the groups defined,
if any are defined. These steps aren't allowed to fail.

Affects: #24
  • Loading branch information
io7m committed Jul 19, 2020
1 parent ec25eb3 commit 3ef9a2f
Show file tree
Hide file tree
Showing 15 changed files with 780 additions and 38 deletions.
Expand Up @@ -47,6 +47,7 @@
import com.io7m.waxmill.machines.WXMEvaluatedBootConfigurationUEFI;
import com.io7m.waxmill.machines.WXMGRUBKernelLinux;
import com.io7m.waxmill.machines.WXMGRUBKernelOpenBSD;
import com.io7m.waxmill.machines.WXMNetworkDeviceBackendType;
import com.io7m.waxmill.machines.WXMOpenOption;
import com.io7m.waxmill.machines.WXMStorageBackendFile;
import com.io7m.waxmill.machines.WXMStorageBackends;
Expand All @@ -70,8 +71,6 @@
import java.util.stream.Collectors;

import static com.io7m.waxmill.machines.WXMBootConfigurationType.WXMEvaluatedBootConfigurationType;

import com.io7m.waxmill.machines.WXMNetworkDeviceBackendType;
import static com.io7m.waxmill.machines.WXMDeviceType.WXMDeviceVirtioNetworkType.WXMTTYBackendType;
import static com.io7m.waxmill.machines.WXMDeviceType.WXMStorageBackendType;
import static com.io7m.waxmill.machines.WXMTTYBackends.NMDMSide.NMDM_HOST;
Expand Down Expand Up @@ -369,11 +368,119 @@ private WXMEvaluatedBootCommands generateGRUBBhyveCommands(
this.generateBhyveCommand(bootConfiguration, attachments);

return WXMEvaluatedBootCommands.builder()
.addAllConfigurationCommands(this.networkDeviceCommands())
.addConfigurationCommands(grubBhyveCommand)
.setLastExecution(bhyve)
.build();
}

private Iterable<WXMCommandExecution> networkDeviceCommands()
{
final var commands = new ArrayList<WXMCommandExecution>();

for (final var device : this.machine.devices()) {
switch (device.kind()) {
case WXM_HOSTBRIDGE:
case WXM_VIRTIO_BLOCK:
case WXM_AHCI_HD:
case WXM_AHCI_CD:
case WXM_LPC:
case WXM_PASSTHRU:
case WXM_FRAMEBUFFER:
break;

case WXM_E1000: {
final var e1000 = (WXMDeviceE1000) device;
this.networkDeviceBackendCommands(commands, e1000.backend());
break;
}
case WXM_VIRTIO_NETWORK: {
final var vio = (WXMDeviceVirtioNetwork) device;
this.networkDeviceBackendCommands(commands, vio.backend());
break;
}
}
}
return commands;
}

private void networkDeviceBackendCommands(
final ArrayList<WXMCommandExecution> commands,
final WXMNetworkDeviceBackendType backend)
{
final var ifconfig = this.clientConfiguration.ifconfigExecutable();

switch (backend.kind()) {
case WXM_TAP: {
final var tap = (WXMTap) backend;
final var tapName = tap.name().value();
commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(tapName)
.addArguments("create")
.setIgnoreFailure(true)
.build()
);

commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(tapName)
.addArguments("ether")
.addArguments(tap.address().value())
.build()
);

for (final var group : tap.groups()) {
commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(tapName)
.addArguments("group")
.addArguments(group.value())
.build()
);
}
break;
}
case WXM_VMNET: {
final var vmNet = (WXMVMNet) backend;
final String vmNetName = vmNet.name().value();

commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(vmNetName)
.addArguments("create")
.setIgnoreFailure(true)
.build()
);

commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(vmNetName)
.addArguments("ether")
.addArguments(vmNet.address().value())
.build()
);

for (final var group : vmNet.groups()) {
commands.add(
WXMCommandExecution.builder()
.setExecutable(ifconfig)
.addArguments(vmNetName)
.addArguments("group")
.addArguments(group.value())
.build()
);
}
break;
}
}
}

private WXMCommandExecution generateGRUBBhyveCommand()
{
final var machineId =
Expand Down Expand Up @@ -750,19 +857,19 @@ private void configureBhyveFlags(
}

private WXMEvaluatedBootConfigurationGRUBBhyve evaluateGRUBConfigurationOpenBSD(
final WXMBootConfigurationType bootConfiguration,
final WXMBootConfigurationType config,
final WXMDeviceMap deviceMap,
final WXMGRUBKernelOpenBSD openBSD)
{
Objects.requireNonNull(openBSD, "openBSD");

final var configLines =
generateGRUBConfigLinesOpenBSD(deviceMap, openBSD);
final var commands =
this.generateGRUBBhyveCommands(config, deviceMap.attachments());

return WXMEvaluatedBootConfigurationGRUBBhyve.builder()
.setCommands(this.generateGRUBBhyveCommands(
bootConfiguration,
deviceMap.attachments()))
.setCommands(commands)
.setRequiredPaths(deviceMap.paths())
.setDeviceMap(deviceMap.serialize())
.setDeviceMapFile(this.grubDeviceMapPath())
Expand Down Expand Up @@ -882,24 +989,26 @@ private WXMEvaluatedBootCommands generateUEFICommands(
this.generateBhyveCommand(bootConfiguration, attachments);

return WXMEvaluatedBootCommands.builder()
.addAllConfigurationCommands(this.networkDeviceCommands())
.setLastExecution(bhyve)
.build();
}

private WXMEvaluatedBootConfigurationUEFI evaluateUEFIConfiguration(
final WXMBootConfigurationUEFI configuration,
final WXMBootConfigurationUEFI config,
final WXMDeviceMap deviceMap)
{
final var requiredPaths = new ArrayList<Path>();
requiredPaths.add(configuration.firmware());
requiredPaths.add(config.firmware());
requiredPaths.addAll(deviceMap.paths());

final var commands =
this.generateUEFICommands(config, config.diskAttachmentMap());

return WXMEvaluatedBootConfigurationUEFI.builder()
.setRequiredPaths(requiredPaths)
.setRequiredNMDMs(deviceMap.nmdmPaths())
.setCommands(this.generateUEFICommands(
configuration,
configuration.diskAttachmentMap()))
.setCommands(commands)
.build();
}

Expand Down
Expand Up @@ -301,7 +301,13 @@ private void executeAndWait(
.addAllArguments(command.arguments())
.build();

this.processes.processStartAndWait(processDescription);
try {
this.processes.processStartAndWait(processDescription);
} catch (final Exception e) {
if (!command.ignoreFailure()) {
throw e;
}
}
}

private String errorRequiredPathsMissing(
Expand Down
Expand Up @@ -97,6 +97,18 @@ default Path zfsExecutable()
.getPath("/sbin/zfs");
}

/**
* @return The "ifconfig" executable path, such as {@code /sbin/ifconfig}
*/

@Value.Default
default Path ifconfigExecutable()
{
return this.virtualMachineConfigurationDirectory()
.getFileSystem()
.getPath("/sbin/ifconfig");
}

/**
* @return The "cu" executable path, such as {@code /usr/bin/cu}
*/
Expand Down Expand Up @@ -152,6 +164,12 @@ default void checkPreconditions()
path -> "zfs executable path must be absolute"
);

Preconditions.checkPrecondition(
this.ifconfigExecutable(),
Path::isAbsolute,
path -> "ifconfig executable path must be absolute"
);

Preconditions.checkPrecondition(
this.virtualMachineConfigurationDirectory(),
Path::isAbsolute,
Expand Down
Expand Up @@ -17,6 +17,7 @@
package com.io7m.waxmill.cmdline.internal;

import com.beust.jcommander.IStringConverter;
import com.io7m.waxmill.machines.WXMInterfaceGroupName;
import com.io7m.waxmill.machines.WXMMACAddress;
import com.io7m.waxmill.machines.WXMTAPDeviceName;
import com.io7m.waxmill.machines.WXMTap;
Expand All @@ -25,6 +26,9 @@

import com.io7m.waxmill.machines.WXMNetworkDeviceBackendType;

import java.util.List;
import java.util.stream.Collectors;

public final class WXMNetworkBackendConverter
implements IStringConverter<WXMNetworkDeviceBackendType>
{
Expand All @@ -49,23 +53,90 @@ public WXMNetworkDeviceBackendType convert(
}

switch (segments[0]) {
case "tap": {
return WXMTap.builder()
.setName(WXMTAPDeviceName.of(segments[1]))
case "tap":
return this.convertTAP(value, segments);
case "vmnet":
return this.convertVMNet(value, segments);
default:
throw this.syntaxError(value);
}
}

private WXMNetworkDeviceBackendType convertVMNet(
final String value,
final String[] segments)
{
switch (segments.length) {
case 3: {
return WXMVMNet.builder()
.setName(WXMVMNetDeviceName.of(segments[1]))
.setAddress(WXMMACAddress.of(segments[2]))
.build();
}
case "vmnet": {
case 4: {
return WXMVMNet.builder()
.setName(WXMVMNetDeviceName.of(segments[1]))
.setAddress(WXMMACAddress.of(segments[2]))
.addAllGroups(this.groupsOf(segments[3]))
.build();
}
default:
default: {
throw this.syntaxError(value);
}
}
}

private Iterable<WXMInterfaceGroupName> groupsOf(
final String text)
{
try {
return List.of(text.split(","))
.stream()
.map(WXMInterfaceGroupName::of)
.collect(Collectors.toList());
} catch (final Exception e) {
throw this.syntaxErrorWith(e, text);
}
}

private WXMNetworkDeviceBackendType convertTAP(
final String value,
final String[] segments)
{
switch (segments.length) {
case 3: {
return WXMTap.builder()
.setName(WXMTAPDeviceName.of(segments[1]))
.setAddress(WXMMACAddress.of(segments[2]))
.build();
}
case 4: {
return WXMTap.builder()
.setName(WXMTAPDeviceName.of(segments[1]))
.setAddress(WXMMACAddress.of(segments[2]))
.addAllGroups(this.groupsOf(segments[3]))
.build();
}
default: {
throw this.syntaxError(value);
}
}
}

private IllegalArgumentException syntaxErrorWith(
final Exception exception,
final String value)
{
return new IllegalArgumentException(
this.messages.format(
"errorInvalidVirtioNetworkBackend",
this.messages.format("networkBackendSpec"),
value
),
exception
);
}

private IllegalArgumentException syntaxError(
final String value)
{
Expand Down
Expand Up @@ -39,18 +39,26 @@ EBNF syntax for Virtio network backends:
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
hexDigit = "a" | "b" | "c" | "d" | "e" | "f" ;
lowerAlpha = ? [a-z] ? ;
upperAlpha = ? [A-Z] ? ;
groupCharacter = lowerAlpha | upperAlpha | "_" ;
groupName = '{' groupCharacter '}' ;
groupList = groupName , '{' "," , groupName '}' ;
macPart = hexDigit , hexDigit ;
macAddress = macPart , ":" , macPart , ":" , macPart , ":" , macPart , ":" , macPart , ":" , macPart ;
tapDeviceName = "tap" , '{' digit '}' ;
vmnetDeviceName = "vmnet" , '{' digit '}' ;
tapDevice = "tap" , ";" , tapDeviceName , ";" , macAddress ;
vmnetDevice = "vmnet" , ";" , vmnetDeviceName , ";" , macAddress ;
tapDevice = "tap" , ";" , tapDeviceName , ";" , macAddress , [ ";" groupList ] ;
vmnetDevice = "vmnet" , ";" , vmnetDeviceName , ";" , macAddress , [ ";" groupList ] ;
Examples:
tap;tap23;d9:63:c0:d9:09:e8
tap;tap0000000000001;d9:63:c0:d9:09:e8
tap;tap23;d9:63:c0:d9:09:e8;wwwUsers,mailUsers,ntpdUsers
vmnet;vmnet23;d9:63:c0:d9:09:e8
vmnet;vmnet00000000001;d9:63:c0:d9:09:e8
vmnet;vmnet23;d9:63:c0:d9:09:e8;wwwUsers,mailUsers,ntpdUsers
]]></entry>

<entry key="deviceSlotSpec"><![CDATA[
Expand Down
Expand Up @@ -16,5 +16,7 @@
value="/etc/waxmill/vm"/>
<Path type="VirtualMachineRuntimeDirectory"
value="/storage/vm"/>
<Path type="IfconfigExecutable"
value="/sbin/ifconfig"/>
</Paths>
</Configuration>

0 comments on commit 3ef9a2f

Please sign in to comment.