Virtual Machine's Networking

This page is about a setting up networking on the virtual machine's networking: enabling full networking on the local link of a virtual machine.

Adjusting the virtual machine's configuration
  • For this part of the process, use the (physical) computer that is running the “virtual machine” software.

Make sure to set the variables that this guide uses for virtual machines. (See: verifying virtualization variable values. If they are unset, check out the documentation that shows the exact values you chose to use. If your documentation is currently lacking that critical detail, then you may benefit by viewing the instructions at setting values related to virtual machines.) That way (by setting those environmental variables), the variables can be used to easily edit the correct script file.

Verify whether you have write access to the file.

Verify file writability

(If you're not familiar with Unix-style permissions, you probably have access to write to the file as long as you have elevated permissions. The main thing to do is to make sure you know the file's location.)

ls -l scriptFileName

e.g.:

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

This should show a bunch of Unix-style permissions (such as -rwxr-xr--), file ownership information, file size, timestamp/date, and the filename. If the response looks more like “ls: exc_*: No such file or directory”, then find the script file. (This problem often occurs if people skipped past earlier instructions and did not actually verifying virtualization variable values. Typos could also cause this.)

Also, verify that the value of VISUAL is set. In the following example, it is presumed that the standard user does not have access to edit the script file, so permissions are being elevated to be able to write the updated file.

Concept
echo VISUAL=${VISUAL}
sudoedit scriptFileName

e.g., the following will first verify virtual machine variable values. If those variables are not set, then use documentation to help get those variables set to the needed values.

echo VMDirBas=${VMDirBas} VMGenNam=${VMGenNam} VMLILNAM=${VMLILNAM}

Then, edit the script file:

echo VISUAL=${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
Change VMNICONETYP
Latest instructions
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
echo VISUAL=${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Find the line that says:

VMNICONETYP=default

Change it:

VMNICONETYP=VMNICTUNTAP
Older notes

These are currently being kept for reference, but should NOT be relied upon! These instructinos were designed for older versions of the script file, and are out of date.

Now, if you're using the script files that have been recommended by this guide, then there is one change to make. Choose one of the following methods:

Editing the script file using sed

First, verify that the expected line exists:

grep -i "^export VMNICONETYP=default$" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

If so, a combination of sudo and sed may be useful.

(These instructions are incomplete. For now, rely on the more manual method instead.)

Using a text editor to modify script file
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
echo VISUAL=${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Find the line that says:

export VMNICONETYP=default

(This is likely the first time that the script file contains the text “VMNICONETYP”.)

Change it:

export VMNICONETYP=VMNICTUNTAP
Old details

(These are just here for temporary reference, and should now be unncessary with the latest version of the script file.)

Until this text is verified to be removable, the recommendation is to click the minimize button (the minus sign) before the “Old details” title.

ALTVLAN

Also, look for where the VMNICONEVLAN and VMNICONEALTVLAN values get defined. For example, look for something like this:

export VMNICONEVLAN=",vlan=1"
export VMNICONEALTVLAN=",vlan=4"

In the example shown, those values don't match, and that is a problem. The reason they don't match is to try to force people to really think about which VLANs they are using. The point is to have devices use a unique VLAN number unless there is actually a desire to have the devices communicate directly to each other.

Make the parts to the right of the equal signs be effectively identical. The following shows a variation of that idea. First, the original lines are preserved as comments. The next line sets the original variable using a machine-unique number. The final line sets the VMNICONEALTVLAN variable to have the same value as whatever VMNICONEVLAN has at that time.

#export VMNICONEVLAN=",vlan=1"
#export VMNICONEALTVLAN=",vlan=4"
export VMNICONEVLAN=",vlan=${VMNUM}"
export VMNICONEALTVLAN="${VMNICONEVLAN}"
Choosing a TUN/TAP device
(The latest script version makes the NIC tun interface name unique, relying on VMNUM to help provide uniqueness.)

The script defaults to using a NIC that is named “tun0”. That may need to be different for other operating systems. Modify that script if needed. (With the default version of the script, this comes after the only copy of the phrase “,ifname=”. e.g., “,ifname=tun0

Apparently only one Qemu NIC can talk to the tunnel interface. So to replicate this concept for other virtual machines, an additional tunnel interface may need to be used. Specify a unique tunnel interface for this machine. (In theory, presumably VMNUM could be used for this. That probably won't be needed for a small number of virtual machines that need to talk to the firewall.)

Making sure the tunnel interface exists
[#tundvnam]: Find the needed tunnel interface name

The plan is to provide a NIC, which is part of a virtual machine, with the ability to communicate with the outside world. To do this, the NIC on the virtaul machine will use a “tunnel”-based network interface, which may be called a (OSI model layer 3) TUN device or a (OSI model layer 2) TAP device (or a TUN/TAP device). To make sure that such a virtual device works as expected, we need to identify the name that software will use when referring to this device. So, figure out it's name, using one of the following methods:

The straight-forward way
Older method

Based on the script's current code, the name of the TUN/TAP device will be based on the machine number. So, figure out the machine number:

grep -i "export VMNUM" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}
Newer method
grep -i "VMNUM" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} | grep X
grep -i "VMNUM" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} | grep X | cut -d = -f 3

Then, consider which NIC is going to be used. For example, on a virtual machine that has only one NIC, the answer would be NIC #1 (the machine's first NIC). For systems with multiple NICs, choose one NIC to focus on. (This process may be repeated, later, for another NIC.)

Now that you know what VMNUM value is used, and which NIC is being used, the name of the TUN/TAP interface can be determined rather easily.

OpenBSD
  • The first NIC of a virtual machine using VMNUM of 44 will use an interface named tun144.
  • The second NIC of a virtual machine using VMNUM of 44 will use an interface named tun244.

So, to figure out the tunnel interface name for a specific NIC on a virtual machine, identify which NIC in the virtual machine is being looked at, and identify the virtual machine number.

The longer way

The longer way is to follow instructions that were placed on a separate page. They were placed on a seperate page so that those longer instructions could be easily skipped if they are unnecessary.

Rather than just following the recommendations mentioned by the shorter (and more straight-forward) way, Finding TUN device name discusses the process of finding out the name of the TUN interface. (That process is a bit time-consuming, and is probably unnecessary when the shorter “straight-forward way” works fine. However, people trying a different operating system might benefit from taking the longer series of steps. Also, the longer way demonstrates how the TUN/TAP device's name can be obtained from the script file.)

Okay, now that the name of the TUN/TAP device has been identified...

The referenced TUN/TAP interface needs to exist. If it doesn't exist yet, that needs to be changed. You can see which TUN/TAP devices currently exist by running:

ls -l /dev/tun[0-9]*

So a check should be made to find out: does the needed tun interface exist?

First, to simplify people's ability to follow these instructions with a minimum of manual customization, make a variable:

[#stcurtun]: Setting CURTUNTP
Sample needing customization
CURTUNTP=tun144

For this example, tun144 is referenced. So, the question is asking whether /etc/tun144 exists. If you are using a different VMNUM or a different NIC number, then the name of the TUN/TAP device will be different from this example. In that case, adjust as needed.)

For the first NIC, you may be able to use this:

CURTUNTP=tun1$(grep -i "VMNUM" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} | grep X | cut -d = -f 3)
echo ${CURTUNTP}

(Then, if a second NIC was made, a similar process could be done by replacing the 1 with a 2.)

If that example command line does not work well, then set CURTUNTP manually, using a variation of the earlier “Sample needing customization” command line that is meant to be customized.

Does the needed tun interface exist? If not, make it.

pwd
cd /dev/
sudo ./MAKEDEV ${CURTUNTP}
cd ${OLDPWD}
pwd
ls -l /dev/tun[0-9]*

Then, see what TUN/TAP devices exist. The new TUN/TAP device should now be visible.

ls -l /dev/tun[0-9]*

Modify the NIC's configuration files to provide a description:

ls -l /etc/hostname.${CURTUNTP}
[ -e /etc/hostname.${CURTUNTP} ] && cpytobak /etc/hostname.${CURTUNTP}
echo description \"VMNUM \#\# NIC \# of ${VMLILNAM}\"| sudo -n tee -a /etc/hostname.${CURTUNTP}
echo ${VISUAL}
sudoedit /etc/hostname.${CURTUNTP}

(The purpose of editing the file is simply to properly customize the numbers. If that was done from the command line, there is no need to edit the file.)

Finally, describe the thing.

ls -l /etc/hostname.${CURTUNTP}
sudo ${SHELL} -c ". /etc/netstart ${CURTUNTP}"
ifconfig ${CURTUNTP}
Creating the network script files
Rationale

When a NIC on the virtual machine is using the TUN/TAP method, there is often some additional configuration that goes along with it. These configuration options can be placed inside some script files that Qemu runs.

If NIC-related script files are specified on the Qemu command line, then they are absolutely required. (This actually feels kind of ironic. With an old version of Qemu, there was an add-on called kqemu that helped to boost the emulator's speed. If the add-on could not be properly found, Qemu could still run by falling back to simply not using the CPU add-on. However, if a NIC configuration script is not found, the system would not boot. The reason that seems funny is that Qmeu's NICs seemed more important for system booting than the CPU, which is not the same prioritization seen on a real physical system.)

The script has some rather full support for the virtual machine's first NIC to be configured some different ways. Also, the script has at least some support for a second NIC and a third NIC. If the virtual machine will only have its first NIC be TUN/TAP, then only required NIC configuration files are the files specified for the device that is going to use the TUN/TAP method. Although the script might have some references to filenames related to a second or third NIC, those references are simply ignored if there is only one NIC, or if the other NICs are not using the TUN/TAP method.

Making necessary directory
Rationale

First, let's see where the script files are being expected. Run this:

$ grep -i ,script= ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Sample output:

,script=${CLIOPTNICSCRAT}/${UPIFSCRNAM}\
,downscript=${CLIOPTNICSCRAT}/${DNIFSCRNAM} "
(And so on... pattern repeats for the second and third NIC)

(Actually, that “sample output” was from some older instructions which did not search for the comma.)

The script files get stored in the ${CLIOPTNICSCRAT} directory. Let's see what that environment variable points at.

$ grep -i CLIOPTNICSCRAT ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Sample output:

export CLIOPTNICSCRAT=${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr
$

Okay, so the script files are placed in a directory named nicscr. That directory needs to exist. The CLIOPTNICSCRAT variable (which indicates where the Command Line Interface's OPTions indicate that the NICCconfiguration SCRipts may be found AT) is just a temporary variable used during the script. That means that the variable does not have its value set outside of the script, so the entire path will need to be typed out in order to make the directory.

  • Make the required directory:
    sudo mkdir ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/

Determining the NIC config script filenames
Rationale

Let's look, once again, at the results of the first grep command from the previous section.

$ grep -i ,script= ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Sample output:

,script=${CLIOPTNICSCRAT}/${UPIFSCRNAM}\
,downscript=${CLIOPTNICSCRAT}/${DNIFSCRNAM} "
(And so on... the shown output can repeat when multiple NICs are shown.)

Based on the output shown in the previous section, the filenames are stored in some (temporary) shell variables named ${UPIFSCRNAM} and ${DNIFSCRNAM}. Determining the exact values of those variables can be a bit of work. However, having some knowledge about the script allows a rather targeted grep command that simplifies things, and shows the critical lines:

$ grep -i -E "VMNICSCRNAMS|IFSCRNAM" ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM} | ${PAGER}

Sample output:

export VMNICSCRNAM="low"
export UPIFSCRNAM=upif${VMNICONEVLANNUM}
export DNIFSCRNAM=dnif${VMNICONEVLANNUM}
[ "X${VMNICSCRNAMS}" = "Xlow" ] &&\
export UPIFSCRNAM=upif0  
[ "X${VMNICSCRNAMS}" = "Xlow" ] &&\
export UPIFSCRNAM=upif0  
(and there are additional output lines, as well)
--More--

(Pressing q can be used to quit most/common ${PAGER} programs.)

One does need to be a bit careful when reviewing such output. In this case, it looks like the values get set to upif0 and dnif0 if the value of VMNICSCRNAMS is set to low. For experienced computer programmers, the indentation helps to imply that as well. That is what is actually happening, in this scenario. However, the results shown here are the results of grep output. Since grep is used to only show some lines, sometimes there are additional lines that are not shown, and sometimes those additional lines may have some rather important details.

So, the important findings, obtained from the process just described, is that the desired filenames for the first NIC's configuration files are upif0 and dnif0. These filenames can be customized, but this guide will rely on the default filenames since that will help to simplify things.

Placing contents in file

Then, make the file. You can try this method:

echo VMDirBas=${VMDirBas} VMGenNam=${VMGenNam} VMLILNAM=${VMLILNAM}
echo \#!${SHELL}
echo \#!/bin/sh| sudo tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
cat ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

Or, if that causes problems, just try using the rather manual way:

echo ${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

Make the contents of the script file be:

#!/bin/sh

Make the file executable, and then copy it.

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/??if0
sudo chmod ug+x ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
sudo cp -p ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0 ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/dnif0

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/??if0

All of this script file editing can be done while the virtual machine is running. The effects will simply occur when the virtual machine gets started again.

  • If the virtual machine is running, then quit the virtual machine so that the NIC can start to be used as a TUN/TAP device when the virtual machine is started.
    • (Note: This is not an instruction to reboot the operating system on the virtual machine. This is an instruction to stop the virtual machine. Have the virtual machine's virtual power be off, or stop the “virtual machine” software.
    • The following may be a way to do that. (Run this on the virtual machine, not the physical system.) “sudo halt -p ”. Alternative ways could involve using the using the Qemu monitor or stopping the “virtual machine” software altogether (using techniques described by adjusting running software).

At this point (after the virtual machine has been entirely stopped), there is still more work to be done to get the networking fully operational. However, at this point, the virtual machine can be started (again). The remaining changes can be easily made after the virtual machine is started.

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

The changes made, so far, will have effectively broken the virtual machine's partial networking capabilities that were available before the changes are made. So, yes, things now seem to be worse. More work is needed to get the networking capabilities fully operational.

Adjusting the physical machine's environment
Know the name of the NIC

Because the script file may use a bunch of variable names, the easiest way to actually find out the name of the NIC may be to just check the Qemu command line, after the machine is running. On the machine that is running the “virtual machine” software, check the command line that was used to start the virtual machine.

The following command shows how this may be done with OpenBSD:

$ ps -auxww | grep -i ${VMLILNAM} | grep -v grep

Sample output:

... -net tap,vlan=###,ifname=tun###,script=...
Some notes about using ps

Note that although the above syntax will work okay with OpenBSD, ps syntax differences are significant enough that no single syntax is preferred by all the Unix implementations. Users of other operating systems may need to adjust the example shown. (Common modifications may include taking out the hyphen right after the word ps and/or removing some parameters, such as one or both of the w characters.)

Multiple redirections are shown. The final redirection is discussed in the section about “Having grep exclude itself”.

The name of the NIC shows up after the “,ifname=”. (If the virtual machine has multiple NICs, be careful to look at the NIC that is being assigned as a TUN/TAP device. If there are multiple, then this process may need to be repeated. In that case, when finding a command line parameter that provides this information, be careful to keep track of which NIC is being configured by that command line parameter. Looking at VLAN settings may help with keeping track of that detail. If the virtual machine has only one NIC so far, then, fortunately, that complexity is not needed at this point.)

Enable Layer 2 tunneling
[#obtplnkz]: Layer 2 tunneling in OpenBSD

This section relies on the value of a variable named CURTUNTP, with the assumption that the CURTUNTP variable was set by some prior instructions. (If setting that variable is problematic, you could just specify the TUN/TAP name directly. Naturally, that interface name should be customized as these directions are followed.) Use the actual TUN/TAP interface name that the virtual machine is configured to use.

echo ${CURTUNTP}

This next section involves running commands on the computer that is running the “virtual machine” software. (So, this would be the “physical” machine.)

(Note: The need to enable “link0” functionality may be particularly prone to being needed on OpenBSD, and not some other operating systems. Users of other operating systems should certainly check the manual pages before blindly trying to run commands shown here.)

The TUN/TAP interface should have a “link local” (MAC-48) address (possibly shown as a “lladdr” in the output of the ifconfig command), and should have these network flags:

BROADCAST,RUNNING,SIMPLEX,LINK0,MULTICAST

If the NIC doesn't show the LINK0 flag, then specify the link0 parameter to ifconfig. This may wipe out certain settings like an interface's configuration to use a certain IP address.

Broken example

Before showing the fix, here an example of things failing:

$ ifconfig ${CURTUNTP}
tun#: flags=20050<POINTOPOINT,RUNNING,NOINET6> mtu 1500
        priority: 0
        groups: tun
        status: active
$ sudo ifconfig tun0 192.0.2.1 netmask 255.255.255.252
$ ifconfig ${CURTUNTP}
tun#: flags=20051<UP,POINTOPOINT,RUNNING,NOINET6> mtu 1500
        priority: 0
        groups: tun
        status: active
        inet 192.0.2.1 --> 0.0.0.0 netmask 0xfffffffc

That whole “ --> 0.0.0.0 ” thing seems kind of odd for people used to seeing output for standard layer 2 devices, such as Ethernet cards and “Wi-Fi”-based adapters. Most regularly-configured network interfaces, which act like Ethernet adapters or Wi-Fi cards, don't show that. The basic reason that this output looks different is described by the OpenBSD manual page for the tunnel driver, which states, “layer 3 tunneling is the default mode. To enable layer 2 tunneling mode, where the tun interface simulates an Ethernet network interface, the link0 flag needs to be set”. So the TUN/TAP device is not a regular Ethernet interface, by default.

However, this situation can be fixed by setting the TUN/TAP device to start acting more like a regular Ethernet interface.

echo ${CURTUNTP}
ifconfig ${CURTUNTP}
sudo ifconfig ${CURTUNTP} link0
ifconfig ${CURTUNTP}

Sample session:

$ sudo ifconfig ${CURTUNTP} link0
$ ifconfig ${CURTUNTP}
tun#: flags=29842<BROADCAST,RUNNING,SIMPLEX,LINK0,MULTICAST,NOINET6> mtu 1500
        lladdr c0:ff:ee:0f:ca:fe
        priority: 0
        groups: tun
        status: active
$

The interface now has the “LINK0” flag. Making this change could have wiped out earlier customizations, like assignment of an IP address, which is why this change is being discussed before further discussion on some of the other network settings.

People who wish to outsmart this guide, you might be tempted to try to combine the link0 flag with some other options, perhaps including the “up” flag. However, OpenBSD manual page for the tunnel driver specifically says, “Note that setting or unsetting the link0 flag causes tun to lose any configuration settings, and that it is not advisable to use the flag with any other parameters.” So, to do things the recommended way, don't combine the link0 option with other options.

Discussion

At this point, if you knew what IP address you would want to use, further configuration could occur. (If the IP addresses have not been determined yet, then worry not: instructions, to do just that, are forthcoming.)

Sample command line (not required, quite yet...)

$ sudo ifconfig tun0 192.0.2.1 netmask 255.255.255.252
$

Running a command like “ ifconfig ifname link0 192.0.2.1 netmask 255.255.255.252 ” (where “link0 is on the same command line as other options) might achieve success, but that is not recommended. OpenBSD manual page for the tunnel driver says, “Note that setting or unsetting the link0 flag causes tun to lose any configuration settings, and that it is not advisable to use the flag with any other parameters.” So, configure any other necessary parameters after flipping the NIC into layer 2 tunneling mode.

Understanding: Why take this approach?

Why force the TUN/TAP device to act as a Layer 2 device? Isn't Layer 3 often more pleasant to work with?

The primary reason is that the TUN/TAP device will be communicating with the virtual NIC that is part of the virtual machine. This virtual NIC has a MAC address, and so the virtual NIC is basically operating using layer 2 communications. When creating a tunnel, both sides should match how they are implemented. Since the virtual machine software is using (Layer 2) MAC-48 addresses, that is what the TUN/TAP device should use.

Perhaps transmitting at Layer 3 would somehow involve less overhead than also emulating Layer 2, but that would require modifying the “virtual machine” software. Although some “virtual machine” software may be “open source”, such a modification is likely to be more work (and, therefore, more time-consuming) than just issuing the link0 option.

Another nice benefit is that a Layer 2 device looks more normal for people who are used to working with Ethernet and/or Wi-Fi network interfaces.

[#vmipadus]: Setting an IP address
Choosing subnets

The default networking model may use some techniques, which may basically be considered to be a form of NAT, to allow the virtual machine to use an IP address that the physical machine also uses. However, this guide is currently discussing how to enable a fuller networking implementation, including being able to have a separate subnet.

This method of assigning network addresses, which is starting to be used, involves using a separate subnet for communication between the virtual machine and the physical machine. That communication will use a subnet which needs to be chosen.

If this network is being designed as part of a project, check the provided project documentation to see if there is a pre-selected subnet that should be used. Otherwise, a guide to help choose subnets is (or will be) at: choosing subnets.

Some examples are shown at sample subnets (used by this guide). Those samples should be customized, because they are coming from the ranges of reserved addresses.

Tasks to do
  • Determine what IPv6 subnet you will use, and what IPv4 subnet you will use.
    • If this information has not yet been decided, then choose the subnets and document them.
    • If this information has been decided, but you don't have the subnets memorized, then pull out the documentation that shows which IP addresses should be used.

Once you know what address to be assigning:

  • Document the subnets in the network's documentation. (This may be less critical in networks where one or more computers will be running some software that reports the subnet to some sort of automatic documentation system. However, for simple networks that don't have such a feature enabled, documenting the subnet may be useful. Such documentation may also be useful before such an auto-report/auto-documenting system is operational.)
  • On the physical host (that is running the “virtual machine” software), set the addresses. (In other words, make the TUN/TAP device use the address that is desired.) The following instructions will discuss how to do that.
Setting the TUN/TAP device
Overview: Why static?

One possible network layout, which is a good choice, is to have the virtual machine rely on DHCP for the NIC that the virtual machine uses to communicate to the Internet. If that virtual machine's NIC is relying on DHCP, then the physical machine's matching NIC (which is a TUN/TAP interface) will need to be configured somehow.

Some people might wonder why automatic address assignment doesn't get used at this point. Well, that doesn't really save effort, for reasons that will be described here.

It does not make sense to try to have both sides rely on DHCP. When DHCP is used, one side needs to rely on some manual configuration (to configure the DHCP server). If both sides tried to use DHCP clients to connect to the remote host, that would mean that manual configuration would still be needed on both sides of the network link, which counters much of the benefit of trying to use DHCP.

Instead of using DHCP, another approach may be to try using IPv6 SLAAC (RFC 4862: IPv6 Stateless Address Autoconfiguration). Well, IPv6 SLAAC uses router discovery (like IPv4's RFC 1256: ICMP Router Discovery Messages), which requires setup by a router. So, IPv6 SLAAC also does not get around the need to do some manual configuration by one system on a network link.

So, every approach with widespread support will require one side of the network connection to use some sort of manual network configuration. This guide will show assigning the IP address on the TUN/TAP device, using a “manual” method of configuration (which is also known as using a “static” method to assign the address).

Manually setting
Rationale

Manual address assignment is an option. Since it will be recommended for the first NIC on the “firewall” system, assigning an address is worth knowing how to do without relying on automatic address assignment methods.

Related resources

If there are challenges when following the upcoming instructions, you may wish to check some of these additional resources: network addressing, manual network addressing, demo subnet.

This section relies on the value of a variable named CURTUNTP, with the assumption that the CURTUNTP variable was set by some prior instructions. (If setting that variable is problematic, you could just specify the TUN/TAP name directly. Naturally, that interface name should be customized as these directions are followed.) Use the actual TUN/TAP interface name that the virtual machine is configured to use.

OpenBSD
Immediate manual method

This approach can be done. However, changes do not necessarily survive reboots.

echo ${CURTUNTP}
$ sudo ifconfig ${CURTUNTP} 198.51.100.1 netmask 255.255.255.252
$ sudo ifconfig ${CURTUNTP} inet6 2001:db8::1 prefixlen 64
$ sudo ifconfig ${CURTUNTP} up
$ ifconfig ${CURTUNTP}
tun#: flags=9843<UP,BROADCAST,RUNNING,SIMPLEX,LINK0,MULTICAST> mtu 1500
        lladdr c0:ff:ee:0f:ca:fe
        priority: 0
        groups: tun
        status: active
        inet6 fe80::0dec:afc0:ffee%tun0 prefixlen 64 scopeid 0xc
        inet 198.51.100.1 netmask 0xfffffffc broadcast 198.51.100.3
        inet6 2001:db8:1::1 prefixlen 64
$

(There may be some variation in the flags. Within the flags, the key thing to look for is the UP flag.)

Surviving method

Current recommendation: If you're not in a hurry, use the “Immediate manual method” below... the post-reboot-survivability will be getting addressed shortly.

This will survive reboots.

echo ${CURTUNTP}
[ -f /etc/hostname.${CURTUNTP} ] && sudo cp -pi /etc/hostname.${CURTUNTP} /etc/hostname-orig${CURTUNTP}

(If even that “backup” file pre-exists, then try again by typing a name that is actually unique. Authors of scripts could rely on a program like mktemp to help create a unique name. Details of that command are discussed by OpenBSD manual page for mktemp).

ls -l /etc/hostname.${CURTUNTP}
cat /etc/hostname.${CURTUNTP}

At this point, the guide temporarily acts as if the file doesn't pre-exist. So instead of trying to change any pre-existing content, new content is just added.

These next commands require heavily customization. (The customization can be done before, or after, the content is placed into a text file.)

echo !echo Now initializing \${if}...|sudo -n tee -a /etc/hostname.${CURTUNTP}
echo link0| sudo -n tee -a /etc/hostname.${CURTUNTP}
echo 198.51.100.1 netmask 255.255.255.252| sudo -n tee -a /etc/hostname.${CURTUNTP}
echo inet6 20081:db8::1 64| sudo -n tee -a /etc/hostname.${CURTUNTP}
echo up| sudo -n tee -a /etc/hostname.${CURTUNTP}
echo description "Connected to virtmachName"| sudo -n tee -a /etc/hostname.${CURTUNTP}

And here is a chance to customize anything needed, including any pre-existing content that existed in the file before adding this new content.

echo ${VISUAL}
sudoedit /etc/hostname.${CURTUNTP}

Customize anything needed. Then check out the results.

sudo ${SHELL} -c " . /etc/netstart ${CURTUNTP} "
ifconfig ${CURTUNTP}
More changes...

To get communication to work, there need to be more changes than just the changes on the system that runs the virtual machine software.

Setting up the other system's networking
Setting up the virtual machine's addressing

One way to do this is to use automatic addressing on the virtual machine. To do this, a DHCP/IPv4 server needs to be set up on the physical machine. Follow the steps on the physical machine:

Handling IPv6

IPv6 automatic addressing is not part of this guide at this time. (This was due to a rush to get some documentation publicly available. If you're familiar with how to get IPv6 automatic addressing working, feel free to use that. Instructions to do so are likely to be added here in the near-ish future.)

For now, just set the IPv6 address manually/statically.

Using automatic addressing

This guide provides details for setting up DHCP/IPv4. That method is recommended at this time, although manually setting the IPv4 is certainly a viable option that some people might actually find to be more attractive.

Go ahead and set up automatic addressing:

TUN/TAP subnet: Using DHCP/IPv4
  • Know what subnet you will be using, and the name of the tunnel interface (NIC) on the physical machine.
  • Make sure that the physical machine has the IPv4 address set. (Until that is done, DHCP/IPv4 certainly won't work.)
  • Then, log into the physical machine (if that isn't done yet).
  • Using the terminal that is logged into the physical machine, see: TUN/TAP subnet: Using DHCP/IPv4.
Testing the configuration

On the virtual machine, run the DHCP/IPv4 client. If the machine isn't started yet, simply starting the virtual machine might cause this to happen. (For instructions on how to start it, refer to the network documentation that has been getting created during this project. If that documentation is not sufficiently providing such instructions, starting an already-created virtual machine.

If the machine is already started, then manual involvement will probably be the fastest way to get the machine to renew its address. Log in and run:

sudo dhclient em0
echo ${?}

Or

sudo ${SHELL} -c ". /etc/netstart em0"
echo ${?}

then

ifconfig em0
Testing the setup

Then, have the machines ping each other. (Note that some operating systems use a command called ping6 for IPv6 addresses.)

Ideally, have the machines ping each other on all three addresses: the IPv4 address, the configured IPv6 address, and the link-local IPv6 address. For the link-local address, there may be a need to specify the identifier (name) of the local NIC. For example, on the physical machine, use: “ ping6 fe80:0dec:afc0:ffee::2%tun0 ”. The IPv6 link local address should be the address of the remote machine, but specify the identifier (name) of the local NIC, not the remote machine's NIC.

Adjusting NIC config startup files

Once communication has occurred, that's a great sign, because it means that the NIC configuration is working, and there aren't problems caused by firewall software running on either machine. However, the task isn't quite done yet; some of the steps that were performed should be done automatically, instead of being done by manually running a command. Take the time to make sure that things will work as nicely after computers get rebooted. Here are some things to check on.

Learning tip

Before applying any of these tips, consider whether the provided details make sense. Actually, that should be routine habit that is being done throughout this entire guide.

Also, think about how closely these instructions match the steps that were taken before, but also how these instructions are slightly different than what was done before. Doing so is likely to substantially help with the overall memorization process, because comparing these steps will involve performing a mental “recall” process of the details that have recently been performed.

Overview of NIC configuration

(Like other sections with “Overview” in their title, this section does not contain commands that need to be run. This is simply documentation about how things work.)

NIC configuration in OpenBSD

NIC initialization can occur by running:

sudo ${SHELL} -c ". /etc/netstart name-of-NIC"

Alternatively,

sudo ${SHELL} -c ". /etc/netstart"

(without specifying the name of the NIC) can be used to initialize all of the NICs on the system. This is basically what /etc/rc does when the system boots.

The /etc/netstart command looks inside the contents of a /etc/hostname.* file for each NIC. The * is the name of an individual network interface. The syntax for such a configuration file is provided by OpenBSD's manual page for “hostname.if”, which is the manual page for the /etc/hostname.* files.

The name of a NIC tends to be based on the name of the driver for the NIC, followed by a number that helps to make the NIC's name different from any other NIC on the same physical system.

(Some of these details are mentioned by OpenBSD FAQ: “Migrating to OpenBSD” section, “Tips for users of other Unix-like Operating Systems”.)

Layer 2 tunnelling

If a process is needed for Layer 2 tunneling, make sure that's taken care of.

Layer 2 tunneling in OpenBSD

On physical machine:

Know the name of the TUN/TAP device that the physical machine uses to communicate with the virtaul machine's NIC. The name of that device needs to be known in order to customize the filenames as required.

Setting a variable

Setting this variable may help some people to be less prone to typing a NIC's name verbatim, instead of performing the proper action of customizing the name of the NIC. There is no technical need to use this variable, but using this variable might help reduce some silly mistakes.

This section relies on the value of a variable named CURTUNTP, with the assumption that the CURTUNTP variable was set by some prior instructions. (If setting that variable is problematic, you could just specify the TUN/TAP name directly. Naturally, that interface name should be customized as these directions are followed.) Use the actual TUN/TAP interface name that the virtual machine is configured to use.

echo ${CURTUNTP}
Review file

If the NIC configuration file already has the desired content, there might not be any need to make any changes. This is not expected to be the case for this particular task, on a brand new machine. However, checking for a need, before trying to perform an action to fix a likely problem, can be a worthwhile habit.

The file might not pre-exist. If the file does not exist on a new machine, don't be alarmed. However, if it does exist, see what text is in the file.

echo CURTUNTP is: ${CURTUNTP} # Simple variable checking
cat /etc/hostname.${CURTUNTP}

In the previous command, like the upcoming commands, make usre the tun0 is customized to match whatever name is actually used for the TUN/TAP device that is being configured here.

Back up any changes

You can skip this step if the file doesn't exist, because there is no file to back up.

This backs up a file by copying it. Note that this is not a thoroughly safe, off-site backup. This isn't even an off-device backup. However, this does provide a relatively convenient way to restore back to an earlier point, if a problem occurs.

echo ${CURTUNTP} is: ${CURTUNTP} # Simple variable checking
ls -Fltr /etc/hostname*.${CURTUNTP} /etc/hostname-orig.${CURTUNTP}
[ -f /etc/hostname.${CURTUNTP} ] && sudo cp -pi /etc/hostname.${CURTUNTP} /etc/hostname-orig.${CURTUNTP}
ls -Fltr /etc/hostname*.${CURTUNTP} /etc/hostname-orig.${CURTUNTP}
Comment

Sometimes, the first step(s) of NIC configuration tend to be fairly silent. This can result in a person wondering just what is causing the computer to basically freeze up. Providing some sort of hint can be quite satisfying.

echo !echo Now initializing \${if}...|sudo -n tee -a /etc/hostname.${CURTUNTP}
Modify the NIC auto-configuration to use link0

Enabling Layer 2 communications (e.g., setting a link0 flag) and assinging addresses:

Make the NIC configuration file contain the command that switches the TUN/TAP device into Layer 2 mode.

echo CURRTUN is: ${CURRTUN} # Simple variable checking
echo !ifconfig \${if} link0|sudo -n tee -a /etc/hostname.${CURTUNTP}
echo ${VISUAL}
sudoedit /etc/hostname.${CURTUNTP}

Since setting link0 might reset other settings, this should probably come before other settings (right after the initial !echo command, which should probably be even higher than the line that sets link0).

Setting IPv4 addresses
On the physical machine
Handling the manual IPv4 configuration

Know the name of the TUN/TAP device.

Review file

If it already has the desired content, there might not be any need to make any changes. This is not expected to be the case for this particular task, on a brand new machine. However, checking for a need, before trying to perform an action to fix a likely problem, can be a worthwhile habit.

echo CURTUNTP is: ${CURTUNTP} # Simple variable checking
cat /etc/hostname.${CURTUNTP}
Backing up any changes

Actually, this very file might have been backed up extremely recently, when handling the Layer 2 tunneling configuration (by adding the link0 flag). If that was just done, so recently, then there may be no need to create yet another backup here. If that wasn't done, then perform a backup here.

This backs up a file by copying it. Note that this is not a thoroughly safe, off-site backup. This isn't even an off-device backup. However, this does provide a relatively convenient way to restore back to an earlier point, if a problem occurs.

echo CURTUNTP is: ${CURTUNTP} # Simple variable checking
ls -Fltr /etc/hostname*.${CURTUNTP} /etc/hostname-orig.${CURTUNTP}
[ ! -f /etc/hostname.${CURTUNTP} ] && sudo cp -pi /etc/hostname.${CURTUNTP} /etc/hostname-orig${CURTUNTP}
ls -Fltr /etc/hostname*.${CURTUNTP} /etc/hostname-orig.${CURTUNTP}
Modify the NIC configuration to set up addressing

The available configuration commands are noted by OpenBSD's manual page for “hostname.if”, which is the manual page for the /etc/hostname.* files.

  • The following examples will be requiring some more customizing. Be careful to customize addresses were needed. (If a reminder is needed about what addresses to use, refer to the network documentation, which is getting created during this project.)
echo inet 192.0.2.1 255.255.255.0 NONE description \"VirtMach\" |sudo -n tee -a /etc/hostname.${CURTUNTP}

(In the above example, every occurrence of the word “NONE” basically indicates that the value is not customized.)

A line that starts with ! will cause the rest of the line to be executed as a command. That could be used for IPv4 configuration (instead of using the shorter syntax that was just demonstrated), and does get used by the following example that demonstrates IPv6 configuration.

echo !ifconfig \${if} inet6 2001:db8::1 prefixlen 64 \# optionalComment |sudo -n tee -a /etc/hostname.${CURTUNTP}
echo !ifconfig \${if} up |sudo -n tee -a /etc/hostname.${CURTUNTP}
Ensuring DHCP/IPv4 server is started

On physical machine, the DHCP/IPv4 should get started. This could be done by the operating system NIC configuration script. However, another spot that makes sense is the “virtual machine” software's NIC configuration script.

ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/*upif0
sudo cp -pi ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0 ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/old-predhcp-upif0
ls -l ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/*upif0

The first line of the text file should identify the shell. If this is a brand new file, the text won't be there yet, so add it to the end of the file, which can be done using this command:

echo \#!/bin/sh| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

(Actually, that text should be at the top of the file. Adding that text to the end of the file only works if the file did not exist yet. Otherwise, plan to move the text as needed.)

Have the script output its name

Then, the name of the NIC should get passed to the script, so the name of the NIC can be referred to as ${1} (or $1). However, just to remove some potential source of confusion, it can be nice to output this:

echo Passed variable is: \${1}| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

That can be helpful if trying to troubleshoot the script.

(If memory serves correctly, sometimes that passed variable would seem to be blank, even if everything else worked as expected. So if the variable is blank, setting it to an expected value might be worthwhile. However, this may have been a quite old version of Qemu. For that matter, memory might not be serving correctly, as perhaps there was another cause for the issue. Regardless, having such a small piece of information that can greatly help troubleshooting is more likely to be substantially helpful than substantially harmful.)

Then, plan to make some more changes to the text file:

echo ${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

If, somehow, the first line of text is not something acceptable like:

#!/bin/sh

... then insert that at the top of the file. (If that line of text appears later, perhaps near the bottom of the file, the extra copy can be deleted. (The fastest way to handle all of this may be to cut the unwanted text that is at or near the end of the file, and then paste that text into the top line.)

Run the following commands to add lines to the text file:

echo echo Ending DHCP server for NIC...| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
echo sudo pkill -f /etc/dhcpd-${CURTUNTP}.conf| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
echo echo Starting DHCP server for NIC...| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
echo sudo dhcpd -c /etc/dhcpd-${CURTUNTP}.conf ${CURTUNTP}| sudo -n tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

If you want to check out the file...

echo ${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
Client-side IPv4 configuration

If you prefer to do the configuration topic-by-topic, then handle the client now. If you prefer to do the configuration by making all of these relevant changes system-by-system, you might choose to delay this until after the physical system's configuration is fully configured. This guide will show the topic-by-topic approach, which involves changing things now.

Note that if the IP addresses have been set, then some of this may be able to be done with SSH. Since routing has not been fully configured, the SSH client may need to be run from the “physical machine” (which is running the “virtual machine” software). If you are used to running the SSH server on a non-standard TCP port, that probably hasn't been configured yet, so the standard TCP port 22 may be the one most likely to be used.

  • This next part is done on the virtual machine.

On the virtual machine, modify the /etc/hostname.* file so that it will run the DHCP client. For example:

ls -l /etc/hostname.em0
sudo cp -pi /etc/hostname.em0 /etc/hostname-old-predhcp.em0
echo !dhclient \${if} | sudo -n tee -a /etc/hostname.em0
Setting IPv6 addresses and routes

Also, if IPv6 configuration wasn't handled yet, do that now, too.

  • Know what IPv6 subnet is used for the “outside VM” interface. (Check your documentation if you don't have that subnet memorized.)
On the physical machine

(Full details are not being provided here at this time. Some earlier instructions about assigning IP addresses may be referenced as a guide to help with how to actually assign an address.)

On the (physical) machine that is running the “virtual machine” software, place the needed commands into the /etc/hostname.tun* file, or the virtual machine software's configuration script for the NIC. The /etc/hostname.tun* file might be a bit nicer, because then a description can be placed in the script, which may help people to identify which virtual machine is intended to be used with a particular TUN/TAP interface.

On the virtual machine

On the virtual machine, place the needed commands in the /etc/hostname.NICNAME* script. For example, if the name of the NIC is em0:

ls -l /etc/hostname.em0
sudo cp -pi /etc/hostname.em0 /etc/hostname-old-preipv6.em0
echo inet6 2001:db8::2 64| sudo -n tee -a /etc/hostname.em0
echo !route add -inet6 default 2001:db8::1| sudo -n tee -a /etc/hostname.em0
  • The first IPv6 address shown here is for the virtual machine.
  • The second IPv6 address shown here, on the route line, is the virtual machine's “default gateway”, which will be the IPv6 of the TUN/TAP interface that this NIC communicates with.
Comment
On the virtual machine
sudoedit /etc/hostname.em0

The first line of the file should be:

!echo Now initializing ${if}...

It seems that the typical standard for this file is to be sourced, so the file does NOT need to start with #! (nor does the file need to have “execute” permissions).

Test
On the physical system

On the “physical” machine that is running the “virtual machine” software:

  • unset customized NIC configuration settings
    OpenBSD
    Simply unset the link0 tag (“ sudo ifconfig ${CURTUNTP} -link0 ”). That will likely lose all of the other settings, too.
  • Then run the NIC config script
    OpenBSD

    (“ . /etc/netstart tun0 ”).

    • Or: “ sudo ${SHELL} -c ". /etc/netstart ${CURTUNTP}"
    ifconfig ${CURTUNTP}
  • Then restart the DHCP server:
    sudo ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0
On the virtual machine

On the virtual machine, run netstart and NIC name.

OpenBSD
(“ . /etc/netstart em0 ”).

That's a pretty thorough test. Some things, like starting the DHCP/IPv4 server, might not be completely verified from that test (depending on what files contain certain commands). Perhaps quitting the virtual machine, or even powering off the physical machine, may be even more thorough. However, doing such a thing is also more time consuming, and is not recommended until the faster tests seem to be working okay.

If you choose to reboot, the reboot is expected to clear out temporary variable values. If you choose not to reboot, it is recommended to unset the following temporary variable (just to do things “cleanly”). “ unset CURTUNTP ”.

...

Additional ideas

(It is currently believed that these “additional ideas” section is not necessary. Starting DHCPd conditionally may be an advantage; the other text is older and not needed any longer...

Here are some additional pointers. (Only one of the following sections is likely to apply for IPv4.)

Notes for DHCP/IPv4 users

Don't forget the link0. (Run this example from outside of the text editor.)

echo ifconfig tun0 link0| tee -a scriptfile

If you're using DHCP, you may wish to start running the DHCP server when Qemu starts up. e.g., start the text editor:

echo ${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/nicscr/upif0

... and then put this in the text file:

ps -auxww | grep -i dhcpd | grep -i tun0 | grep -v grep >> /dev/null || sudo -n dhcpd -c /etc/dhcpd-tun0.conf
Using manual addressing

If you wish to keep using manual address assignment, you can do so. It is no longer recommended (after seeing text in the manual, which recommends to not do this) to combine link0. This text should be updated/removed.... In fact, the link0 and the address assignment can be combined in a single line. Here is an example that uses the custom script name that this guide has been using:

(First, verify virtualization variable values.)

echo ifconfig tun0 link0 192.0.2.1 netmask 255.255.255.252| tee -a ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

If there's any other changes you wish to make to how the machine starts up, then go ahead and make them.

echo ${VISUAL}
sudoedit ${VMDirBas}/execbin/${VMGenNam}/${VMLILNAM}/sysstart/exc_${VMLILNAM}

Near communication works

At this point, hopefully communication is occurring between the virtual machine and the TUN/TAP interface on the physical machine. If not, Qemu documentation: section called “Network emulation” (section 3.7) discusses networking, so perhaps that may be helpful.

Once the virtual machine is able to communicate with the physical machine, The virtual machine might not be communicating to the Internet yet. However, that is likely to be caused by factors such as the physical machine not forwarding packets, or NAT/IPv4 not being enabled. Some or all of those reasons might be fixable simply from the physical host. The good news is that fixing those things usually does not require changing the Qemu command line, so there isn't generally a need to stop the virtual machine software while those issues are troubleshot.

Additional resources

These instructions about virtual machine networking is currently focused on Qemu, and is meant to provide simple step-by-step instructions for people using the process described by the rest of this guide. For people who are using other approaches, there might be some further information available at some additional resources.

Note that these resources are not part of this guide, and so some of these might be less specific/focused on simply providing step-by-step reproducable instructions. Instead, they may discuss things from a more “high level” process, discussing concepts more than just implementation details. Of course, this guide welcomes you to return if desired.

Clean-up:
unset CURTUNTP
That wraps up this page.
Remaining notes on this page are no longer recommended... current intentions for these notes are to have these notes be purged after a some more quality checking...
[#dhcponbt]: Automatically use DHCP

These notes are no longer recommended... Earlier instructions have been updated to have this be started from upif0, which feels like a more sensible place for such configuration. Skip this section of instructions.

Automatically starting DHCP server

These instructions are based on the idea that the phyiscal server is running the DHCP server. If that's the case, then the physical machine's configuration will need to add this. Here are some specifics for various operating system(s):

OpenBSD: Automatically starting the DHCP server
grep -i dhcpd_flags /etc/rc.conf*

The part before the asterisk is a filename. There might be multiple matching filenames (/etc/rc.conf and /etc/rc.conf.local).

Back up config

Before modifying a configuration file, the recommended process is to back up the file. So let's do that first. Actually, even before that, let's see if there even is a file to back up.

ls -l FILETOBK=/etc/rc.conf.local

If it's there, then go ahead and back up.

export FILETOBK=/etc/rc.conf.local

See: creating an archive file.

Then, figure out which NIC will be used. The following sample command line expects that the NICs name is appropriately customized.

echo dhcpd_flags=\"-c /etc/dhcpd-tun0.conf tun0\"| sudo -n tee -a /etc/rc.conf.local

(The previous command lines are samples, and are based on instructions found from instructions discussed in the section about starting the DHCP server.)

Note: this approach is only expected to work if there is a just a single DHCP/IPv4 server running on the system. For more complex setups, the best bet may be to just run the server using a file called /etc/rc.local (instead of modifying a variable in a /etc/rc.conf.local file, which is a different file). Of course, if you plan to do that, the best, generally recommendable process will be to back up that configuration file before editing it.

Finally, note that this work work unless the NIC has an IP address. If the TUN/TAP device was getting the IP address set by a Qemu script, that probably won't work desirably because the DHCP/IPv4 server will start first, and will notice the lack of an IP, and will quit before the Qemu program is run. The solution is to adjust the NIC configuration script which will set the IP address before the DHCP/IPv4 server starts.

ls -l FILETOBK=/etc/hostname.tun0
cat /etc/hostname.tun0

If it's there, then go ahead and back up.

export FILETOBK=/etc/hostname.tun0

Finally, edit it.

echo !ifconfig \$if link0| sudo -n tee -a /etc/hostname.tun0
echo inet 192.0.2.1 255.255.255.252 NONE description \"TUN/TAP for Qemu\"| sudo -n tee -a /etc/hostname.tun0
echo up| sudo -n tee -a /etc/hostname.tun0
ls -l /etc/hostname.*

A key reason to ls -l the file is to notice the permissions. If it is different than the permissions for the other NICs, well, the netstart command is likely to fix that for you okay.

Testing it...

Rebooting is one way, but here's a more direct way to try to test just the things that were just changed.

sudo ${SHELL} -c ". /etc/netstart tun0"
echo ${?}
ls -l /etc/hostname.*

and if you want to try to re-run the DHCP/IPv4 server...

sudo dhcpd -c /etc/dhcpd-tun0.conf tun0
echo ${?}

If you're trying to use a different operating system, then it will be helpful to know details about the process that occurs when that operating system is starting up. There may be some helpful details at system startup.

Configuring the virtual machine
Automatically starting DHCP client

Now, we're going to adjust the details of the virtual machine. (If you're not logged into the virtual machine, then log into that machine. The next instructions describe changes that are intended to be performed on the virtual machine.)

First, follow backing up NIC config. That describes the steps to check what configuration file pre-exists, and handle the task of performing a backup of that file, as well as seeing the contents of the file.

Connections should be made before trying to run DHCP client. Presumably this is taken care of for physical machines using wired connections, as well as virtual machines. For physical machines using Wi-Fi, this means that the configuration file should contain the details for trying to establish a Wi-Fi association before the DHCP client is started. So, put those lines in the file, first. Details about wireless may be described by #netconn.

The following line tells the client to use DHCP/IPv4 on a NIC named em0.

echo dhcp| sudo -n tee -a /etc/hostname.em0

(Note: Sometimes a default file might include a syntax similar to “DCHP NONE NONE NONE”. That's fine too. For additional related documentation, one may refer to OpenBSD manual page for NIC configuration file. An offline copy of that same documentation can be seen by running: “ man hostname.if ”.

Then, the best way to test that configuration file may be to use it:

sudo ${SHELL} -c ". /etc/netstart nic#"

e.g.:

sudo ${SHELL} -c ". /etc/netstart em0"

By using that process, there probably won't be any need to be trying to manually run just the DHCP/IPv4 client. However, if there is a desire to, here's the command and syntax:

sudo dhclient em0
Handling IPv6 on the client

The following sets a statically-assigned IPv6 address when the network interface named em0 is initialized. If a different network interface name is being used, customize the filename at the end of this command line:

echo !ifconfig \${if} inet6 2001:db8::1 prefixlen 64| sudo -n tee -a /etc/hostname.em0

If an operating system is not listed above, then accomplishing automatic configuration may require an understanding of how the operating system starts up. In such a case, you may find some details by checking to see if there are configuration files, or automatically started programs, in the documentation at system startup.


SCRATCH NOTES:
# The "-net nic" creates the NIC, which lets the guest operating system see
# the NIC, while the other -net options focus on how such a NIC communicates
# to other devices. It is like "-net nic" installs a network card, and the
# other -net options focus on the wiring/connectivity.


actively running “virtual machine”. (So, if it is still booting up, wait for that to complete. Then, log in. If you can't see the machine's output, consider re-visting the instructions at using Qemu's VNC, or other details from the seeing “virtual machine” video output section.)