Tag Archives: arp

Wireless bridging for Virtual Machines (e.g. KVM)

Background

Recently I’ve started using KVM (= VMM = libvirt = virt-manager).

I’m used to VirtualBox, where there in an option to define the network to be bridged, i.e. the Virtual Guests appear to be in the same LAN as the Host.

Alas, the official documentation says:

Important Note: Unfortunately, wireless interfaces cannot be attached to a Linux host bridge, so if your connection to the external network is via a wireless interface (“wlanX”), you will not be able to use this mode of networking for your guests.

But, I believe that “In Linux, the impossible just takes a little more time”, and here begins our story.

(If you’re really impatient, jump down to “Putting It All Together” – but then don’t blame me if you don’t understand…)

Possible solutions

(The Quest Begins)

dedoimedo has a nice article about it.

His first solution – to use ‘brctl’ just doesn’t work for me. (That’s probably why the official document says it’s impossible).

His second solution (‘Alternative setup’) is to create a new Network Interface, and route it to the Wireless Interface.

Indeed, this is a good solution for some use cases, but it’s not good for me. This is routing, while I need bridging.

The main difference is that routing operates on Layer 3 (=IP) while bridging operates on Layer 2 (=MAC, Ethernet). That means that with routing we have 2 separate networks, that can speak with each other. But they are 2 different LANs, with different IP networks. While bridging makes them a unified LAN, with all IP addresses on the same subnet.

His third (and last) solution sounds much better (he calls it ‘very dirty hack) –create the Virtual Guests new subnet with IP addresses that belong to the Host’s original network. That sounds interesting, but suffers from a routing problem:

In order to understand the problem, let’s describe the following network:

“External”: Wireless Router – 192.168.1.1

“External”: Printer         – 192.168.1.121

“External”: Virtual Host    – 192.168.1.149

“Internal”: Virtual Guest   – 192.168.1.180

Now, suppose the printer (.121) wants to send an IP packet to the Guest (.180). The printer knows that it’s in the same LAN, so it has to find out what is it “real” Hardware Address (=Layer 2 = MAC Address). In order to find this out, it sends an ARP (=Address Resolution Protocol) broadcast packet, asking “Who has .180 IP Address, please tell me what’s your MAC address”. ARP dictates that only the owner of that IP Address should response, so Virtual Host ignores the packet. Furthermore, it wouldn’t route it to the Virtual Guest, because no one told him to route Broadcast packets – it only routes IP packets send specifically to .180.

Bottom line – members of the “external” network won’t be able to send packets to members of the “internal” network.

(Calling For Help)

At that point, I’ve posted a superuser.com question. MariusMatutiae offered a new solution, of Bodhi Zazen.

Bodhi Zazen, in turn, referred to a very interesting article describing using Proxy ARP.

Actually, I haven’t tried Bodhi Zazen’s solution, because it seemed to be too complicated for my needs. (installing new package, defining tap device, manually allocating IP address and defining routes…)

However, his link was very helpful, so thanks 🙂

The Man In The Middle

When configuring a machine with Proxy ARP it start answering ARP questions for other IPs!

And that can fill the gap of Dedoimedo’s last solution – we just need to tell our Virtual Host to answer ARP questions regarding the Internal Network of the Virtual Guests with its own MAC address.
Thus, when our printer (.121) tries to reach Guest (.180) it sends an ARP question; but now the Proxy ARP (.149) will say – “Hey, It’s me”, and the printer will send packets destined to Guest (.180) with the Proxy’s (.149) MAC address. When the Virtual Host gets the packet, it will see it has Internal Network IP, and it already knows to forward packets to it.

Putting It All Together

To summarize, we have 2 phases here:

  1. Defining a new interface, according to Dedoimedo’s last solution
  2. Creating a Proxy ARP

Defining the new interface

(Before we begin, it’s recommended to shut down the Guest machine)

You can refer to dedoimedo here, but I’ve also put some screenshots:

First, create a new Network using Virt Manager’s GUI.
The Name doesn’t matter; all the other details are critical.
They’ll probably differ according to your network configuration – but the critical point here is that the new internal network is a subnet of your old external network, without interfering with it. 


After this phase, it’s a good practice to verify that we didn’t ruin anything with the host connectivity:

$ ping -c 4 www.google.com

And verify that you get reply. (if not – read a few more lines)

The routing table might also be interesting:

$ route

Kernel IP routing table

Destination Gateway Genmask Flags Metric Ref Use Iface

192.168.1.160 * 255.255.255.224 U 0 0 0 virbr1

192.168.1.0 * 255.255.255.0 U 2 0 0 wlan0

192.168.122.0 * 255.255.255.0 U 0 0 0 virbr0

default 192.168.1.1 0.0.0.0 UG

We can ignore the ‘virbr0’ line – it’s libvirt’s default NAT interface; not interesting for us.
All the other lines are important, and should like somewhat like here:
‘virbr1’ route for the internal network
‘wlan0’ route for the external network
‘default’ route for all others – The Big Internet

Pay attention that if ‘virbr1’ and ‘wlan0’ shouldn’t have the same Destination. If they do, that means that you didn’t define the virtual network correctly, and it might ruin your external connectivity.
If that’s the case, remove the new network, and re-define it with different parameters.

If everything is OK, we can connect remove the old Network device of our Machine, and create a new one using our new Interface.


And The Interesting Part – the PROXY ARP!

How do we define a Proxy ARP?

Well, the first article I read about it suggested this command:

/sbin/arp -i eth1 -Ds ${NETWORK} eth1 netmask ${NETMASK} pub

Which I translated to this:

arp -i wlan0 -Ds 192.168.1.180 wlan0 pub

The ‘netmask’ part is omitted because the Arp Man page says:

NOTE: As of kernel 2.2.0 it is no longer possible to set an ARP entry for an entire subnet. Linux

instead does automagic proxy arp when a route exists and it is forwarding. See arp(7) for details.

I didn’t understand at that point how the “automagic proxy arp” should work, so I ignored it temporarily.

And…

It works!

Hey there, it’s not perfect yet!

I know  🙂

There are 3 minor disadvantages here (that I know of; I’d be glad to hear more)

  1. The command I wrote is not for an entire subnet, it should be issued for each host in the internal network
  2. According to the Arp Man page, this command is being deprecated
  3. (I’m not sure about it, as I haven’t tried it yet) I assume that the ARP table wakes up clean every boot, so our proxy isn’t permanent, and should be added to some startup script

The future is here…

After I finished all of these, I found that Linux Advanced Routing & Traffic Control HOWTO has also an interesting article regarding Proxy ARP (apparently more modern than TLDP’s August 2000 one)

That probably explains the un-understood “Automagic” part mentioned in the Man page:

With Linux 2.4/2.5 (and possibly 2.2), this possibility has been withdrawn and has been replaced by a flag in the /proc directory, called ‘proxy_arp’. The procedure for building a pseudo-bridge is then:

  1. Assign an IP address to both interfaces, the ‘left’ and the ‘right’ one
  2. Create routes so your machine knows which hosts reside on the left, and which on the right
  3. Turn on proxy-ARP on both interfaces, echo 1 > /proc/sys/net/ipv4/conf/ethL/proxy_arp, echo 1 > /proc/sys/net/ipv4/conf/ethR/proxy_arp, where L and R stand for the numbers of your interfaces on the left and on the right side

Sound easy, but I can’t check it now, so hold on for updates.

3 Comments

Filed under Linux