2018-09-09

Two logical interfaces on one physical, on Ubuntu 18.04 without Netplan

If my ISP-provided home gateway allowed DNS aliases to be configured, I'd get it to map foo.home to bar.home, a headless server. foo.home is meant to be present in my home network and in my relatives', to identify a host providing write access at each site to a library of photos, videos and music that are synchronized between sites. The home gateway has no such aliasing feature, so I've done it by adding an interface on the bar.home host. The new interface looks like a different host to the gateway, so it can have a different name. It happens to get a different IP too.

I could have achieved largely the same with the spare wireless interface, but why use up airwaves to travel 1 foot between a static host and the access point? I could have bought a USB Ethernet dongle, but I did it without any extra hardware or using up a socket on the gateway by creating a virtual interface faux0 piggybacked on the physical wired interface enp3s0. Here's what I did on Ubuntu Server 18.04.

From Netplan to Ifupdown

Ubuntu 18.04 uses Netplan by default. Its configuration files match /etc/netplan/*.yaml. Older Ubuntus use ifup and ifdown which read configuration from /etc/network/interfaces, and ifup -a is run at boot to bring up all marked interfaces. I'd hoped to configure Netplan to set up two logical interfaces on one physical one, with different MAC addresses, and each making DHCP requests with different names, but it doesn't seem to have any way to do that. According to Netplan documentation, installing the package ifupdown is sufficient to disable Netplan:

sudo apt-get install ifupdown

Now you need configuration to make ifupdown perform Netplan's duties:

# In /etc/network/interfaces
auto lo
iface lo inet loopback

auto enp3s0
iface enp3s0 inet dhcp

The interface name enp3s0 is the host's sole wired Ethernet device. Yours might have a different name, perhaps the traditional eth0. You can list all interface names with:

ip link show

Just to make sure, I also renamed 01-netcfg.yaml to 01-netcfg.yaml-disabled. That's the only file I found in /etc/netplan/, so that really should render it inert, as Netplan doesn't modify interfaces it does not match in its configuration.

Things that didn't work

I also investigated removing the package netplan.io, but was told that that would also remove ubuntu-minimal. I suspected that might be a bad idea. There's also a package netplan, which also provides the /usr/sbin/netplan binary, but it was not installed.

Creating the second interface

With ifupdown now responsible for interface configuration at boot, define the new interface:

# In /etc/network/interfaces
auto lo
iface lo inet loopback

auto enp3s0
iface enp3s0 inet dhcp

auto faux0
iface faux0 inet dhcp
pre-up ip link add faux0 link enp3s0 address XX:XX:XX:XX:XX:XX type macvlan
pre-up /sbin/sysctl -w net.ipv6.conf.faux0.autoconf=0
post-down ip link delete faux0

I named the new, virtual interface faux0. It's created with an ip link command just before the interface comes up, and similarly deleted just after being taken down, using the pre-up and post-down directives.

The pre-up /sbin/sysctl is not essential, but disables SLAAC on the interface, which is appropriate for virtual interfaces. Don't know whether I'll need it, but the interface seemed to be accumulating a lot of IPv6 addresses, so I'll try it and see.

The new interface has a distinct MAC address XX:XX:XX:XX:XX:XX, specified as it is created. I've borrowed one from a device I know will not be seen on my home network, but there's probably a better strategy, something that a virtualization system employs, perhaps. It's not something I've looked into yet. Maybe someone will explain in a comment, because I get a lot of those. The interfaces file format also has a hwaddress setting, but it seemed to have no effect.

The new interface is configured to request a DHCP lease with the name foo:

# In /etc/dhcp/dhclient.conf
interface "faux0" {
  send host-name "foo";
  send dhcp-client-identifier 1:XX:XX:XX:XX:XX:XX;
}

I've thrown in a dhcp-client-identifier setting, but I'm not sure how vital it is. It seems you can use any string (with quotes if necessary), and it's just to stop the gateway from thinking the two DHCP clients are the same, leading to both interfaces coming up as under the same name in the gateway's web interface, making it less clear what you're port-forwarding to. However, that could have been caused in my case by bad data cached in the gateway, flushed out by leaving the server off while deleting the entries in the gateway. I'm going to leave them the setting in for now, as it seems harmless. I explicitly set an identifier for the main interface too, for completeness.

Things that didn't work

Setting the hostname for the interface with a hostname directive in /etc/network/interfaces didn't work because dhclient doesn't recognize it. Hence, it is set in dhclient's own configuration.

Setting the MAC address with a hwaddress also didn't work.

ARP flux

ARP flux can be a problem. Both interfaces can respond to ARP requests for either of their IPs. My home gateway then detects that both IPs map to the same MAC, and therefore to the same hostname, so both names end up resolving to the same IP. The other address, though it gets properly assigned to the right interface, never gets used. Functionally, this is fine, and actually meets the goal of having DNS aliases. However, it messes up the rendition and editing of port-forwarding rules in the gateway. If you have a rule forwarding to the disused MAC, its IP has no name, so the IP is displayed as the destination, not the hostname. It's also impossible to select that IP as a destination, because you can only select by name on this particular gateway.

To fix this, it's possible to disable the interfaces responding to ARP requests on behalf of each other, and the following seems to the right combination of settings to avoid one of the interfaces going dead (according to this serverfault article):

# In /etc/sysctl.conf
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.all.rp_filter=2

You can test these temporarily with the likes of:

sudo sysctl -w net.ipv4.conf.all.arp_ignore=1
sudo sysctl -w net.ipv4.conf.all.arp_announce=2
sudo sysctl -w net.ipv4.conf.all.rp_filter=2

Things that didn't work

Not setting rp_filter results in one of the interfaces being unable to receive traffic, effectively leaving it dead.


That should be it. Rebooting should put that into effect, but without rebooting, this should be enough (from the machine's console, not remotely!):

sudo ifdown enp3s0
sudo ifup enp3s0
sudo ifup faux0

In summary:

  • Install ifupdown.
  • Remove or rename Netplan files matching /etc/netplan/*.yaml to disable Netplan.
  • Create entries in /etc/network/interfaces to take over Netplan's duties, and augment to set up the extra interface.
  • Tell dhclient to use foo instead of the machine's hostname.
  • Take steps to prevent ARP flux.

Happy now?


[Edited to include notes on ARP flux.]

No comments:

Post a Comment