Configuring VirtualBox VMs for OpenvSwitch Networking
Summary
I use OpenvSwitch as the networking solution for my project https://github.com/gstanden/orabuntu-lxc and it comes bundled with Orabuntu-LXC. But what if you install Orabuntu-LXC and you want to also run some VirtualBox VMs and you want those VMs to be on the same network as the LXC Linux containers and you want them to get their dynamic DHCP and DNS from the same source as the LXC containers? Actually, this is relatively easy to do and this blog is intended to show how that is done. This was all done and tested on Oracle Linux 7 UEK4 OS. On other OS YMMV but this should work the same for CentOS7 and RedHat7. All bets are off if you go to Linux6 however - typically procedures are needed there. This is Linux7 specific here.
Getting OpenvSwitch Onto Oracle Linux 7
Use my guide here for building OpenvSwitch from source on Oracle Linux 7 UEK4.
Setup Dynamic DNS DHCP
Sometime I will add details on this but right now it's outside the scope of this particular blog post for time constraint reasons. I have some posts though that include how to do that for example here. Once dynamic DHCP/DNS solution is in place the VirtualBox VM's can be hooked up.
Configure /etc/nsswitch.conf on the Host
This is needed just to make sure that /etc/hosts doesn't override your DNS values. If you find everything is working ok (DHCP is issuing an IP address and DNS lookup works for that IP address and DNS name) but ssh is not working using the DNS name, then check to see if /etc/hosts has some different IP for that same DNS name and then remove it from /etc/hosts and edit /etc/nsswitch.conf to make sure resolver uses DNS first.
[root@ol72 openvswitch]# cat /etc/nsswitch.conf
#
# /etc/nsswitch.conf
#
# An example Name Service Switch config file. This file should be
# sorted with the most-used services at the beginning.
#
# The entry '[NOTFOUND=return]' means that the search for an
# entry should stop if the search in the previous entry turned
# up nothing. Note that if the search failed due to some other reason
# (like no NIS server responding) then the search continues with the
# next entry.
#
# Valid entries include:
#
# nisplus Use NIS+ (NIS version 3)
# nis Use NIS (NIS version 2), also called YP
# dns Use DNS (Domain Name Service)
# files Use the local files
# db Use the local database (.db) files
# compat Use NIS on compat mode
# hesiod Use Hesiod for user lookups
# [NOTFOUND=return] Stop searching if not found so far
#
# To use db, put the "db" in front of "files" for entries you want to be
# looked up first in the databases
#
# Example:
#passwd: db files nisplus nis
#shadow: db files nisplus nis
#group: db files nisplus nis
passwd: files sss
shadow: files sss
group: files sss
#initgroups: files
#hosts: db files nisplus nis dns
hosts: dns files myhostname
# Example - obey only what nisplus tells us...
#services: nisplus [NOTFOUND=return] files
#networks: nisplus [NOTFOUND=return] files
#protocols: nisplus [NOTFOUND=return] files
#rpc: nisplus [NOTFOUND=return] files
#ethers: nisplus [NOTFOUND=return] files
#netmasks: nisplus [NOTFOUND=return] files
bootparams: nisplus [NOTFOUND=return] files
ethers: files
netmasks: files
networks: files
protocols: files
rpc: files
services: files sss
netgroup: files sss
publickey: nisplus
automount: files
aliases: files nisplus
[root@ol72 openvswitch]#
VLAN the OpenvSwitch Ports
I like to use VLAN on my OpenvSwitch to partition network traffic. You don't have to use VLAN. If you do use VLAN the script which configures the OpenvSwitch at boot needs to have the correct VLAN tags for the ports the VM and/or the LXC containers will use as shown below. Also, there is more detail about this script here. Note that you can add more VLAN's to your "trunks" parameter (comma separated) and then you can have VM's on different VLAN using the same switch just in separate trunks.
Just a side note that I prefer using these iptables rules to establish WAN rather than bonding the openvswitch bridge directly to a physical interface because this way whatever networking was already in place on the desktop or server should be unaffected and continue to work. I've built my openvswitch solutions with this goal in mind of making them additive not disruptive. That being said YMMV so test first in a VM to be sure this is compatible with your existing networking setup if you want to preserve that networking.
[root@ol72 openvswitch]# cat crt_ovs_sw1.sh
#!/bin/bash
ip tuntap add s1 mode tap
ip tuntap add s2 mode tap
ip tuntap add s3 mode tap
ip tuntap add s4 mode tap
ip tuntap add s5 mode tap
ip link set s1 up
ip link set s2 up
ip link set s3 up
ip link set s4 up
ip link set s5 up
ovs-vsctl add-br sw1
ovs-vsctl add-port sw1 s1
ovs-vsctl add-port sw1 s2
ovs-vsctl add-port sw1 s3
ovs-vsctl add-port sw1 s4
ovs-vsctl add-port sw1 s5
ip link set up dev sw1
ip addr add 10.207.39.1/24 dev sw1
ip route replace 10.207.39.0/24 dev sw1
ovs-vsctl set port sw1 trunks=10
ovs-vsctl set port sw1 tag=10
ovs-vsctl set port s1 tag=10
ovs-vsctl set port s2 tag=10
ovs-vsctl set port s3 tag=10
ovs-vsctl set port s4 tag=10
ovs-vsctl set port s5 tag=10
# GLS 20140825 Get active external interface dynamically at boot. Tested & works with {wlan0, eth0, bnep0} on Ubuntu 14.04.1 Desktop x86_64.
# GLS 20140825 Interface "bnep0" is Blackberry Z30 OS10 Bluetooth Tether.
### BEGIN Get Active EXTIF Dynamcially. ###
function GetInterface
{
ifconfig | egrep -B1 'inet' | egrep -A1 'enp|wlp|wlan|eth|bnep' | sed '$!N;s/\n/ /' | sed 's/ */ /g' | cut -f1,7 -d' ' | sed 's/ addr//' | head -1 | cut -f1 -d':'
}
Interface=$(GetInterface)
function GetIP
{
ifconfig | grep -A1 $Interface | grep inet | sed '$!N;s/\n/ /' | sed 's/ */ /g' | cut -f3 -d' '
}
### END Get Active EXTIF Dynamically. ###
echo ' IP: '$(GetIP)
echo 'Interface: '$(GetInterface)
INTIF="sw1"
EXTIF=$(GetInterface)
echo 1 > /proc/sys/net/ipv4/ip_forward
# clear existing iptable rules, set a default policy
iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -P OUTPUT ACCEPT
iptables -F OUTPUT
iptables -P FORWARD DROP
iptables -F FORWARD
iptables -t nat -F
function CheckIptablesRulesCount {
sudo iptables -S | grep FORWARD | grep sw1 | wc -l
}
IptablesRulesCount=$(CheckIptablesRulesCount)
while [ $IptablesRulesCount -ne 0 ]
do
iptables -D FORWARD -i $EXTIF -o $INTIF -j ACCEPT > /dev/null 2>&1
iptables -D FORWARD -i $INTIF -o $EXTIF -j ACCEPT > /dev/null 2>&1
IptablesRulesCount=$(CheckIptablesRulesCount)
done
# set forwarding and nat rules
iptables -A FORWARD -i $EXTIF -o $INTIF -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
# iptables -t nat -A POSTROUTING -o wlp4s0 -j MASQUERADE
service dhcpd start
service named restart
[root@ol72 openvswitch]#
Configure the VirtualBox VM to use OpenvSwitch
This part is done simply with the VirtualBox GUI (unless you have more than 4 network interfaces to configure with OpenvSwitch on VirtualBox). The switch itself should look like this if using VLAN tags.
[root@ol72 openvswitch]# ovs-vsctl show
05eaf5dd-98f5-422d-8de7-966049e48c00
Bridge "sw1"
Port "s4"
tag: 10
Interface "s4"
Port "sw1"
tag: 10
trunks: [10]
Interface "sw1"
type: internal
Port "s5"
tag: 10
Interface "s5"
error: "could not open network device s5 (No such device)"
Port "s3"
tag: 10
Interface "s3"
Port "s1"
tag: 10
Interface "s1"
Port "s2"
tag: 10
Interface "s2"
ovs_version: "2.5.1"
[root@ol72 openvswitch]#
Networking the VirtualBox VM to OpenvSwitch is done as shown below. Be sure to select one of the ports on the switch (in this case "s2") that has the correct VLAN tag and also be sure to set "Promiscuous Mode" to "Allow All" and be sure to use "Bridged Adapter". (The fields that are greyed out are only greyed out because I took this screenshot when the VirtualBox VM was running).
Configure /etc/dhcp/dhclient.conf in VM (optional)
If for any reason the VM does not configure /etc/resolv.conf correctly at boot, it is possible to tell the resolver to use a different nameserver. This is done by configuring /etc/dhcp/dhclient.conf on the VM (not the host) as shown below.
[root@uekulele1 ~]# cat /etc/dhcp/dhclient.conf
prepend domain-name-servers 10.207.39.1;
[root@uekulele1 ~]# cat /etc/resolv.conf
# Generated by NetworkManager
search orabuntu-lxc.com
nameserver 10.207.39.1
[root@uekulele1 ~]#
Edit /etc/ssh/sshd_config in VM (optional)
If you find that login to the VM is very slow (you can confirm this by using ssh -vvv username@vm-dns-name) then it may be the issue with GSSAPI authentication. In that case you can optionally edit /etc/ssh/sshd_config and set these two parameters as shown below to make login lightening fast. Note this has nothing to do with OpenvSwitch per se, it's just a login thing but it's included here anyway. Also note that UseDNS has nothing to do with the DNS name resolution - your VM will still use your DNS to resolve hostnames. You can lookup what UseDNS does if interested.
[root@uekulele1 ~]# cat /etc/ssh/sshd_config
# $OpenBSD: sshd_config,v 1.93 2014/01/10 05:59:19 djm Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
# The default requires explicit activation of protocol 1
#Protocol 2
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024
# Ciphers and keying
#RekeyLimit default none
# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
SyslogFacility AUTHPRIV
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#RSAAuthentication yes
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
PasswordAuthentication yes
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
#KerberosUseKuserok yes
# GSSAPI options
# GLS 2016-10-12 turning off GSSAPI <-- Set GSSAPI to no
# GSSAPIAuthentication yes
GSSAPIAuthentication no <-- Set to no here
GSSAPICleanupCredentials no
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
#GSSAPIEnablek5users no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several
# problems.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation sandbox # Default for new installations.
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ShowPatchLevel no
#UseDNS yes
# GLS 2016-10-12 Be sure UseDNS is no. <-- Turn off UseDNS
UseDNS no <-- Here.
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Accept locale-related environment variables
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
# override default of no subsystems
Subsystem sftp /usr/libexec/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
[root@uekulele1 ~]#
The pool of switch ports s1, s2, s3, s4 ... can be used to connect 4 different VirtualBox VM network interfaces. If the VMs aren't running at the same time, you can even re-use ports for different machines although I don't recommend this. You can add more ports as you need them by just editing crt_ovs_sw1.sh and adding more ports. You can also give the swtich ports meaningful names like "myserverhostname" although don't let them get too long I think there may be some character length limits on names of ports (but not sure about that).
One side note is that VMs work differently with OpenvSwitch than LXC containers do. With the VM's we can setup the ports ahead of time and then just use them by bridging the VM adapter to an OpenvSwitch port. In the case of LXC containers, the containers create the port 'on-the-fly' when starting so we don't pre-create them like this for LXC containers (but that's another story).
Troubleshooting
If you can ssh to the VirtualBox VM ok from the host using the DNS name, then that means your DNS solution is working properly (but you can do nslookup on both the DNS name and IP address of the VirtualBox VM to be sure). Then if your /etc/resolv.conf looks ok in the VM (points to the DNS/DHCP nameserver and has the right domain) and of course is similar to the /etc/resolv.conf on the host, then that should be OK too. But if still you cannot resolve names using "nslookup" or "ping" in the VM (but works properly on the host) then the problem is probably iptables rules on the host needed for the VM to network properly if "nslookup" and "ping" are not resolving in the VM, or it could be also sysctl.conf parameters as shown below. Be sure you have the following set on the HOST (not the VM) as shown below. This is discussed in more detail at Venu Murthy's excellent post here.
[root@ol72 Downloads]# sysctl -p
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.ip_forward = 1
[root@ol72 Downloads]# cat /etc/sysctl.conf
# System default settings live in /usr/lib/sysctl.d/00-system.conf.
# To override those settings, enter new settings here, or in an /etc/sysctl.d/<name>.conf file
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
# GLS 20141226 http://thenewstack.io/solving-a-common-beginners-problem-when-pinging-from-an-openstack-instance/
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0
# GLS 20141226 http://thenewstack.io/solving-a-common-beginners-problem-when-pinging-from-an-openstack-instance/
net.ipv4.ip_forward=1
[root@ol72 Downloads]#
Be sure you have iptables rule set correctly on the host also. The crt_ovs_sw1.sh script should have set the iptables rules that are at boot (see my post on openvswitch-as-a-service on Oracle Linux 7 here) required but if not, you can try a rule of this form as shown below which should be run on the HOST (not on the VM). In this example the "External Interface" is a wireless interface "wlp4s0" but it could also be a wired interface enpxxx or a bluetooth tether interface bnepxxx etc.. As noted, the crt_ovs_sw1.sh script should take care of identifying which interface has an ip address and assign this automatically and run the iptables rules onboot, but on a server with multiple active IPs it might need some manual adjustment to get the crt_ovs_sw1.sh script set to what is required and so replacing variables with literal interface names in crt_ovs_sw1.sh is of course just fine if needed for a specific requirement.
iptables -t nat -A POSTROUTING -o wlp4s0 -j MASQUERADE
If you want to install LXC Linux container software as a next step, use my guide for building LXC on Oracle Linux 7 from source here.