qemu-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Connection of a qemu guest to the 'net.


From: Berto Furth
Subject: Re: Connection of a qemu guest to the 'net.
Date: Wed, 17 Mar 2021 20:36:14 +1100
User-agent: Cyrus-JMAP/3.5.0-alpha0-206-g078a48fda5-fm-20210226.001-g078a48fd

Hi Peter,

This is a long email. In answering your question I got on a roll and ended up 
writing an essay. 

In summary, to answer your last question which was "br0 needs a configuration? 
tap0 needs to relate to br0? How?"   tap0 needs to be associated to br0 so that 
your QEMU guest can send traffic over it and the traffic can be processed by 
the host. In addition you can associate other interfaces to br0, like your 
hosts's real/physical eth0 interface, or other tap interfaces connected to 
other guests, so that your guest can communicate directly with the real world 
and/or other guests.

Anyway your email got me thinking and here's what I wrote down. This isn't 
necessarily all directed to you because I suspect you've got a fair bit of 
Linux and networking experience so some of this stuff will already be known to 
you. Let me know if it makes sense or if it's rubbish....



A bridge interface (e.g. br0) is a way for Ethernet traffic to pass unmodified 
and unprocessed between interfaces that are members of the bridge. If you had 
two real Ethernet interfaces on your host system (eth0, eth1), you could make 
your host act like an Ethernet "switch" by configuring your eth0 and eth1 
interfaces to be members of the same bridge interface (br0). Traffic heard on 
eth0 would be forwarded to eth1 and vice versa.  (N.B. Look into bridging or 
switching tables for more details about how forwarding decisions are made). 
This means that the physical Ethernet networks connecting to eth0 and eth1 are 
*different* Ethernet segments, but they will be in the *same* IP subnet.

In this kind of bridging setup eth0 and eth1 do NOT have IP addresses 
configured but the bridge interface (br0) does. This is because the ethX 
interfaces are just acting as conduits. The virtual br0 interface is the means 
that the host will use to perform IP communication to the devices connected to 
both the eth0 and eth1 networks.

When people hear that eth0 and eth1 don't need IP addresses they sometimes get 
a bit confused. Think of a managed Ethernet switch (I'm sure you have one in 
your network if you're the type of person who uses QEMU). You don't give every 
port on your Ethernet switch a separate IP address, right? Instead you give the 
switch a single management IP address that can be accessed via all the ports of 
the switch. In the same way if you wanted to make your host perform network 
bridging between eth0 and eth1, then you wouldn't give both eth0 and eth1 an IP 
address. Instead you give an IP address to the bridge interface (br0) which has 
both eth0 and eth1 as member interfaces. The host uses this single IP address 
configured on the br0 interface to communicate with devices on both Ethernet 
segments.


In QEMU a tap interface (e.g. tap0) is just a conduit that conveys network 
traffic between your guest and the host. It doesn't need an IP address because 
all it's doing is passing traffic. Of course, your QEMU guest still needs to be 
configured with an IP address within the guest operating system itself.

What we need to do is make the tap interface a member of a host bridge 
interface so that the traffic can either be heard by the host, or forwarded off 
to a real Ethernet network, or forwarded off to other guests using other tap 
interfaces (e.g. tap1). We do this by simply making the tap interface a member 
of the bridge interface, and then the guest can communicate with all the 
devices which are connected to the other member interfaces associated with the 
bridge.


I'm going to illustrate by looking at three separate styles of configuration 
using QEMU and tap interfaces. QEMU has the ability to work with preexisting 
tap interfaces, or to dynamically create them at startup. It also has the 
ability to dynamically create bridge interfaces or work with preexiting 
bridges. 

I'm using a setup where QEMU automatically creates tap interfaces when it 
starts and bridge interfaces are preexisting. In my view is the best way to go 
because it means that you can have multiple instances of QEMU running and 
communicating with each other and they can all dynamically generate and destroy 
their own tap interfaces as they need them rather than relying on there being 
pre-configured tap interfaces in place for them all. By keeping the bridge 
configuration separate to QEMU, you are more easily able to customize how the 
bridge interfaces behave.

Note 1 : In the scenarios below I'm only showing the commands to temporarily 
modify host networking behavior. Unless otherwise noted, these changes will not 
survive a host reboot. I'm taking this avenue because the steps for modifying 
network configurations to survive reboots is very specific to each 
distribution. Hopefully if you are able to understand what we're doing with 
these command line examples you can look up how to perform the equivalent 
operations using the configuration tools and files of your specific 
distribution.

Note 2 : In all the command line examples below I first present the modern 
iproute2 (ip) commands, then following that I use the older ifconfig / brctl / 
route commands. You only need to perform one of the two sets of commands to get 
the same result. 

Note 3 : If you get errors running the commands related to creating bridge 
interfaces then you may need to recompile your kernel to include bridging 
support.


Scenario 1 : You only want the guest(s) to be able to communicate with the host 
but not with the real network (simplest)

First we need to create a bridge interface (e.g. br9) on the host and give it 
an IP and IPv6 address that don't conflict with any existing IP subnets 
configured on the host. In this example we'll give the bridge interface an IP 
address of 10.0.9.1 / 255.255.255.0. We also give the interface an IPv6 address.

Note that we can call the bridge anything we like (br0, br54, bridgeA, 
myqemubridge) but brX is the normal interface name format.

root@lfs:~# ip link add br9 type bridge
root@lfs:~# ip link set br9 up
root@lfs:~# ip address add 10.0.9.1/24 dev br9
root@lfs:~# ip address add fd99:9999:9999:9999::1 dev br9

OR

root@lfs:~# brctl addbr br9
root@lfs:~# ifconfig br9 10.0.9.1/24
root@lfs:~# ifconfig br9 inet6 add fdaa:aaaa:aaaa:aaaa::1/64

Next we need to make sure we have a script that will help QEMU automatically 
attach a newly created tap interface to the bridge when QEMU comes up. The 
default name for this script is "qemu-ifup" and there are plenty of great 
examples of what you can put in that script. For example

https://en.wikibooks.org/wiki/QEMU/Networking#qemu-ifup

Below are my very simple versions of the "qemu-ifup" script. The first version 
uses "iproute2", and the second uses the older "ifconfig / brctl" commands. You 
only need to pick one of those. You should also create a "downscript" called 
"qemu-ifdown" that gets executed when QEMU exits and deletes the tap interface, 
but it can just be blank if you're following this guide.


#! /bin/sh
# qemu-ifup script to bring a network (tap) device for qemu up 
# iproute2 version

# You must specify the preexisting bridge interface you want the tap
# connected to in the variable "bridge" set below.
bridge=br9

ip=$(which ip)
echo $0 connecting $1 to $bridge
ip link set "$1" up
ip link set "$1" master "$bridge"
exit

- - - - - - - - - - - - - - - - - - - -

#! /bin/sh
# qemu-ifup script to bring a network (tap) device for qemu up 
# ifconfig / brctl version

# You must specify the preexisting bridge interface you want the tap
# connected to in the variable "bridge" set below.
bridge=br9

brctl=$(which brctl)
echo $0 connecting $1 to $bridge
ifconfig "$1" 0.0.0.0 up
brctl addif $bridge "$1"
exit

- - - - - - - - - - - - - - - - - - - -

#! /bin/sh
# qemu-ifdown script to execute just before the tap interface is removed.
# Normally this script is empty.
echo $0 removing tap interface $1
exit


Remember to make the scripts executable with a command like

chmod a+x qemu-ifup qemu-ifdown


Finally run QEMU with a command line that enables tap networking. For example

qemu -machine [whatever] ...... -nic tap

qemu -machine [whatever] ...... -netdev 
type=tap,id=testnet,script="./qemu-ifup",downscript="./qemu-ifdown" -global 
driver=[whatever-ethernet-driver-you-use],property=netdev,value="testnet" 


After the guest is running you should make sure your guest operating system is 
configured with an IP address in the same subnet as the br9 interface on the 
host. In this case an example of a valid guest IP address would be 
10.0.9.101/24. The guest would also typically be configured to use the host's 
br9 address (10.0.9.1) as a default gateway. After this the guest and host 
should be able to have full network communication with each other, but the 
guest won't be able to connect with hosts in the "real" network. The same 
should go for other guests you launch in other QEMU sessions on the same host.


Scenario 2 : You want the guest(s) to get direct (bridged) access to the host's 
real Ethernet network. (Most useful in my view)

This is similar to scenario 1 except you must also make your real host Ethernet 
interface (e.g. eth0) a member of the same bridge as the tap interfaces.

This means that you need to reconfigure your system so that eth0 no longer has 
an IP address. This is because the eth0 interface will now act as a mere 
conduit just like the tap interfaces. Your nominated bridge interface will get 
the IP address associated with the host on the real Ethernet network. 

In most cases real host Ethernet interfaces get addresses via DHCP however 
since that's configured and done in a wide variety of ways depending on your 
distro I'm going to assume here that your eth0 is currently using a static IP 
address. That being said it should not be hard for you to find out how to 
configure your bridge interface as a DHCP client in your specific distro if 
that's what you would like.

First you need to remove the IP address from eth0. Next create a new bridge 
interface (e.g. br7), then associate your eth0 interface with it. Finally you 
need to move the IP configuration that was on eth0 over to the new bridge 
interface (br7). In the example below eth0 originally has an ip address of 
10.0.1.22/24 so we move that to the br7 interface. The IPv6 addresses will take 
care of themselves via IPv6 auto configuration (SLAAC) assuming that's enabled 
in your real network. The other thing we do in this example is reconfigure the 
host's default gateway that was in place (10.0.1.1) as this will be 
automatically removed when we delete eth0's IP address.

Also note that at the point where you remove eth0's IP address the host will 
lose network connectivity via eth0. For that reason it's probably best to 
perform these commands on the host's console or via a different network 
interface.

root@lfs:~# ip address show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group 
default qlen 1000
    link/ether dc:XX:XX:XX:XX:55 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.22/24 brd 10.0.1.255 scope global eth0
       valid_lft forever preferred_lft forever
     inet6 2001:XXXX:XXXX:XXXX:deXX:XXff:feXX:XX55/64 scope global dynamic 
mngtmpaddr
       valid_lft 2591816sec preferred_lft 604616sec
    inet6 fe80::deXX:XXff:feXX:XX55/64 scope link
       valid_lft forever preferred_lft forever
root@lfs:~# ip route
default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.22
root@lfs:~# ip address del 10.0.1.22/24 dev eth0
root@lfs:~# ip link add br7 type bridge
root@lfs:~# ip link set br7 up
root@lfs:~# ip link set eth0 master br7
root@lfs:~# ip address add 10.0.1.22/24 dev br7
root@lfs:~# ip route add default via 10.0.1.1

OR

root@lfs:~# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500  metric 1
        inet 10.0.1.22  netmask 255.255.255.0  broadcast 10.0.1.255
        inet6 2001:XXXX:XXXX:XXXX:deXX:XXff:feXX:XX55  prefixlen 64  scopeid 
0x0<global>
        inet6 fe80::deXX:XXff:feXX:XX55  prefixlen 64  scopeid 0x20<link>
        ether dc:XX:XX:XX:XX:55  txqueuelen 1000  (Ethernet)
        RX packets 847  bytes 71856 (70.1 KiB)
        RX errors 0  dropped 6  overruns 0  frame 0
        TX packets 137  bytes 17757 (17.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@lfs:~# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.0.1.1        0.0.0.0         UG    0      0        0 eth0
10.0.1.0        *               255.255.255.0   U     0      0        0 eth0

root@lfs:~# ifconfig eth0 0.0.0.0
root@lfs:~# brctl addbr br7
root@lfs:~# brctl addif br7 eth0
root@lfs:~# ifconfig br7 10.0.1.22/24
root@lfs:~# route add default gw 10.0.1.1


After running these commands your host should have regained connectivity to the 
real network however eth0 will just be a "conduit" interface and all the IP 
configuration will now belong to bridge interface br7. 

We can now connect QEMU guest tap interfaces to the bridge br7 in the same way 
as in Scenario 1. All we need to do is modify the "qemu-ifup" script to use 
"bridge=br7" instead of "br9" which we used in Scenario 1. Guests should now 
have full access to the "real" Ethernet network that eth0 is physically 
connected to.

If you like, you can keep multiple kinds of bridge networks (e.g. "br9" and 
"br7") active on your host so that you can launch guests connecting to either 
type of bridged network depending on your requirements.


Scenario 3 : You want the host to act as a router between a "guest subnet" and 
the "real" network. (complicated)

In this scenario guests will be able to access the "real" network but they will 
be on a different IP subnet to the eth0 network. The host will have 
responsibility for routing / forwarding IP packets between the "guest subnet" 
and the rest of the world. This also means that a router on the real network 
will need to be reconfigured so that it knows to route packets to the guest 
subnet via the host's eth0 interface. If the router on the real network is not 
reconfigured to know how to route to the guest network then packets will make 
it from QEMU guests to real devices, but then packets transmitted from devices 
in the real network won't make it back to the guests.

In this scenario we first need to make sure that the host is configured for IP 
routing / IP forwarding. 

This can be done on the command line as follows for both IPv4 and IPv6

root@lfs:~#echo 1 > /proc/sys/net/ipv4/ip_forward
root@lfs:~#echo 1 > /proc/sys/net/ipv6/conf/all/forwarding

On many (but not all) systems you can make this change permanent across reboots 
by editing /etc/sysctl.conf to include the lines

net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding=1

Next, we need to proceed exactly as in Scenario 1 so I won't rehash those steps 
here.

Let's say we have created bridge interface br9 with IP address 10.0.9.1/24 as 
per the example in Scenario 1. Let's also say that our eth0 interface has an IP 
address of 10.0.1.22.

This means that on our external router on the "real" network we need to 
configure a route for network 10.0.9.1/24 via 10.0.1.22. In cisco terminology 
that's

ip route 10.0.1.0 255.255.255.0 10.0.9.1

You'd also need to do the same for the IPv6 network if you're using IPv6.


Note that you can extend Scenario 3 (and Scenario 1) by making the host a DHCP 
server for the guests. In addition the "radvd" daemon can be installed on the 
host so that guests can be automatically configured for IPv6. Setting these 
services up is not normally hard, and makes things very convenient in regards 
to not having to manually configure the IP stacks on your guests. However since 
configuring and installing these tools is quite specific to each distro we 
won't discuss it here. The only thing I want to stress about DHCP and radvd is 
that you only set them up to work on your bridge interface which connect to 
guests and NOT on your Ethernet interfaces that connect to the "real" network. 
If you accidentally get these services running on an interface connecting to 
your real network they will conflict with the already running services and your 
real network will be in chaos!!

There's no need for setting up your host as a DHCP or "radvd" server in 
Scenario 2 because your guests will have access to these services via the real 
network where these services should already be working and active.




I hope some of this helps Peter. All the best.

Berto.


On Wed, 17 Mar 2021, at 03:30, peter@easthope.ca wrote:
> Hello Berto,
> 
> Thanks for the reply.
> 
> In the following, joule is the qemu host.
> 
> From: Berto Furth
> Date:         Tue, 16 Mar 2021 21:18:08 +1100
> > I'm assuming you're also using dynamically created "tap" interfaces in your 
> > setup. 
> 
> tap0 is created in the qemu host when it boots, by a line in 
> /etc/crontab. I don't do anything to remove tap0.  Therefore tap0 
> will exist until something catastrophic happens or the system shuts down.
> 
> peter@joule:/home/peter$ grep tap0 /etc/crontab
> @reboot root ip tuntap add mode tap tap0
> 
> > That is, when QEMU starts it's creating a tap interface to funnel 
> > Ethernet traffic to and from the guest...so a command line something like
> >
> > -netdev 
> > type=tap,id=testnet,script="./qemu-tap-up",downscript="./qemu-tap-down"
> 
> There is no file "./qemu-tap-up" or similar.  There is no script 
> option in the qemu command.  /etc/network/interfaces has a stanza for 
> tap0.  tap0 exists and has an ip address.
> 
> peter@joule:/home/peter$ ip addr show tap0
> 6: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP 
> gr
> oup default qlen 1000
>     link/ether 56:06:3e:f1:4e:13 brd ff:ff:ff:ff:ff:ff
>     inet 172.23.6.1/24 brd 172.23.6.255 scope global tap0
>        valid_lft forever preferred_lft forever
>     inet6 fe80::5406:3eff:fef1:4e13/64 scope link
>        valid_lft forever preferred_lft forever
> 
> > You can do routing, but you would still need to use a bridge interface for 
> > the 
> > dynamically created "tap" interface to connect to!! 
> 
> Accepted.  Thanks.
> 
> Incidental note.
> I have a LAN with a Linux router machine and a machine on a subnet.  
> The router has Shorewall and dnsmasq.  Routing from the subnetted 
> machine to the router host and to the Internet works.  No bridge is 
> required for that.
> 
> > It's just that rather than setting up the bridge interface to do 
> > bridging between the tap and the "real" ethernet of the host, you'd 
> > set up the bridge interface to be a separate routed interface on your 
> > host.
> 
> I don't really understand that distinction.  According to 
> https://en.wikipedia.org/wiki/Network_bridge "A network bridge is a 
> computer networking device that creates a single, aggregate network 
> from multiple communication networks or network segments. This 
> function is called network bridging."
> 
> Apparently qemu requires a bridge to connect the guest.  Communication 
> can not be routed between guest and host without a bridge.  (?)
> 
> br0 is created in the qemu host by another line in /etc/crontab.
> 
> peter@joule:/home/peter$ grep br0 /etc/crontab
> @reboot root ip link add name br0 type bridge
> 
> br0 exists analogous to tap0 but does not have an IP address.
> 
> peter@joule:/home/peter$ ip addr show br0
> 7: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group 
> default qlen 1000
>     link/ether 76:da:52:dd:52:45 brd ff:ff:ff:ff:ff:ff
> 
> > Routing is a bit more difficult to setup than simple bridging because 
> > you have to first make sure your host is configured for routing (most 
> > aren't by default) and then you have to make sure your "real" 
> > networking infrastructure knows about the new QEMU guest subnet and 
> > how to route to it (via your host).
> > 
> > See the following URL for an example script to run when your QEMU tap 
> > interface is created that allows routing and you'll see how much extra 
> > effort it is to get routing (in this case with NAT) working compared 
> > to simple bridging.
> > 
> > https://wiki.qemu.org/Documentation/Networking/NAT
> 
> This linux router has shorewall which has a configuration file 
> /etc/shorewall/snat containing this line.
> MASQUERADE  172.23.6.0/24  $NET_IF
> 
> Other subnets work that way.
> 
> If tap0 is configured with address 172.23.6.2 in 
> /etc/network/interfaces, SNAT should work for the qemu guest.
> 
> > If you just want QEMU to do simple NAT between the guest and the 
> > "real" network then just use "SLIRP" as per
> > 
> > https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29
> 
> Will use SLIRP if necessary.  Not sure it's necessary.
> 
> > (I haven't tested it...I always use tap and bridging)
> 
> I want to do that also.  From the above you see that tap0 and br0 
> exists in the qemu host here. dnsmasq provides DNS.  Shorewall 
> provides SNAT.  The qemu command has this option.
> 
> -nic tap,model=ne2k_pci
> 
> Nevertheless no connection.
> 
> peter@joule:/home/peter$ ping 172.23.6.1
> PING 172.23.6.1 (172.23.6.1) 56(84) bytes of data.
> 64 bytes from 172.23.6.1: icmp_seq=1 ttl=64 time=0.043 ms
> 
> --- 172.23.6.1 ping statistics ---
> 1 packets transmitted, 1 received, 0% packet loss, time 0ms
> rtt min/avg/max/mdev = 0.043/0.043/0.043/0.000 ms
> 
> peter@joule:/home/peter$ ping 172.23.6.2
> PING 172.23.6.2 (172.23.6.2) 56(84) bytes of data.
> From 172.23.6.1 icmp_seq=1 Destination Host Unreachable
> 
> --- 172.23.6.2 ping statistics ---
> 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
> 
> At least one ingredient is missing.  
> 
> br0 needs a configuration?  
> 
> tap0 needs to relate to br0?  How?
> 
> Ideas welcome.
> 
> Thanks,                             ... P.
> 
> -- 
> cell: +1 236 464 1479            Bcc: peter at easthope. ca
> VoIP: +1 604 670 0140
> 
> 
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]