Bug 1723367 - [RFE] connect <interface> to a pre-created host macvtap device
Summary: [RFE] connect <interface> to a pre-created host macvtap device
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux Advanced Virtualization
Classification: Red Hat
Component: libvirt
Version: 8.1
Hardware: Unspecified
OS: Unspecified
unspecified
medium
Target Milestone: rc
: ---
Assignee: Laine Stump
QA Contact: yalzhang@redhat.com
URL:
Whiteboard:
Depends On:
Blocks: 1747928 1758964
TreeView+ depends on / blocked
 
Reported: 2019-06-24 11:32 UTC by Dan Kenigsberg
Modified: 2020-11-14 05:40 UTC (History)
12 users (show)

Fixed In Version: libvirt-5.6.0-7.el8
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
: 1747928 (view as bug list)
Environment:
Last Closed: 2020-02-04 18:28:48 UTC
Type: Feature Request
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)
the coverage report for the patches (29.81 KB, text/html)
2019-10-28 10:03 UTC, yalzhang@redhat.com
no flags Details


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2020:0404 0 None None None 2020-02-04 18:29:57 UTC

Description Dan Kenigsberg 2019-06-24 11:32:30 UTC
Currently, libvirt takes upon itself to create a macvtap device on top of a host interface. I'd like libvirt to be able to do less.

I'd like to create a macvtap device and configure it to my liking (in a CNI), and make it available to libvirt which runs as a normal user in its own netns.

I would like to specify the device it as a <source dev='macvtap0'> element, and have libvirt connect it to qemu.

Comment 1 Laine Stump 2019-08-08 03:59:59 UTC
Today I was finally able to put together a proper test for this, and successfully started a guest with session-mode (unprivileged/non-root) libvirtd that used a pre-created macvtap device. My test was this:

(as root)
# ip link add link p14p1 name mymacvtap0 address 52:54:00:12:12:12 type macvtap mode bridge
# ip link set dev mymacvtap0 up
# chown laine:laine /dev/tap$(ip link show mymacvtap0 | head -1 | cut -d: -f1)

(as user laine)

# virsh define [a guest with the following interface definition]

   <interface type='direct'>
      <mac address='52:54:00:12:12:12'/>
      <source dev='p14p1' mode='bridge'/>
      <target dev='mymacvtap0'/>
   </interface>

# virsh start [that guest]

If the macvtap device didn't exist, or the mac address of the macvtap device is different from what's in the definition, it would log an error. Conversely, the setting of source dev and mode are ignored - that's only used during device creation, and my patch bypasses device creation completely when the device already exists.

This could maybe be made a bit friendlier in the error reporting department (e.g., right now it will complain that it can't create a non-existing device rather than saying that it can't create it due to insufficient privileges), but it would be at least good enough to try it out and see if this is what you want to do.

I'll send a patch upstream tomorrow AM (US EST), and try to make either a RHEL8 or Fedora 30 rpm for you if it would be useful.

(It's a very minor patch once I got enough time to actually think through it).

Comment 2 Laine Stump 2019-08-19 04:27:35 UTC
I thought about this more before sending a patch, and realized I didn't want the simple patch because it is a hack.

In the meantime I've also found that a small modification to the device setup for conventional tap devices makes precreated standard taps usable from a non-privileged libvirt too - as with macvtap devices, it the tap device is created as owned by the uid of the process running libvirtd, and as long as we avoid attempting to set the MAC address or modify the interface flags (e.g. to set IFF_UP or MULTIQUEUE) then it can be opened by the unprivileged libvirtd and consumed successfully by qemu.

I'm now thinking that this could all be exposed to libvirt's consumers with an extra option to <interface type='ethernet'>, e.g.:


     <interface type='ethernet'>
       <target dev='tapdevname' unmanaged='yes'/>
       ...
     </interface>

Any network device declared like this would be opened, but no setup would be done (no mac address setting, no interface flags, no MTU).
This could work for both macvtap and standard tap even though they each use a different method of opening the fd for the device - just check first whether or not it's a macvtap device. )There could be disagreement with this, since in the past type='ethernet' was used only for standard tap devices.)

Comment 3 Laine Stump 2019-08-28 01:50:18 UTC
I just posted patches upstream that support use of precreated tap and macvtap devices by an unprivileged libvirt.

 https://www.redhat.com/archives/libvir-list/2019-August/msg01256.html

(I did switch the attribute name to "managed" :-)

I don't know that this can be reviewed in time for the feature freeze for 5.7.0, since that will be happening within 12-16 hours.

Comment 7 Laine Stump 2019-09-09 19:01:44 UTC
Patches have been pushed upstream to support an unprivileged libvirtd using pre-created standard tap and macvtap devices:

commit 1b46566eed0c9c23251d05c8fedb3522d711f5c0
Author: Laine Stump <laine>
Date:   Mon Aug 26 01:24:08 2019 -0400

    util: new function virNetDevMacVLanIsMacvtap()
    
commit 3d21ff72e0e37ebfb3305c93c003ab0ec36b98e4
Author: Laine Stump <laine>
Date:   Mon Aug 26 01:51:40 2019 -0400

    util: make a couple virNetDevMacVlan*() functions public
    
commit 3c049fadce477869af1830a0af8e25ec7c427fe8
Author: Laine Stump <laine>
Date:   Tue Aug 27 12:18:35 2019 -0400

    qemu: reorganize qemuInterfaceEthernetConnect()
    
commit 33d02dfca67bd8fd65a50631f7aaae07215ed7cd
Author: Laine Stump <laine>
Date:   Tue Aug 20 22:53:11 2019 -0400

    conf: use virXMLFormatElement for interface <target>
    
commit 77f72a86159beccc6cfff3392a2aca78485729be
Author: Laine Stump <laine>
Date:   Wed Aug 21 16:42:41 2019 -0400

    conf: new "managed" attribute for target dev of <interface type='ethernet'>
    
commit 7cd0911e1a6c1b1cfe57c6e375077c689424a009
Author: Laine Stump <laine>
Date:   Mon Aug 26 00:24:34 2019 -0400

    qemu: support unmanaged target tap dev for <interface type='ethernet'>
    
commit 51d66b92e6c4873016409f90fbe257fb23bd4bc0
Author: Laine Stump <laine>
Date:   Mon Aug 26 13:05:19 2019 -0400

    qemu: support unmanaged macvtap devices with <interface type='ethernet'>

Comment 9 Laine Stump 2019-09-10 19:33:57 UTC
This patch isn't needed for building on RHEL, but will be needed by anyone who wants to apply it to a platform that doesn't support macvtap:

commit c803e05870f459948efa7dce97682d0169a525f7
Author: Michal Privoznik <mprivozn>
Date:   Tue Sep 10 11:24:19 2019 +0200

    virnetdevmacvlan: Provide stubs for macvlan related functions

Comment 13 yalzhang@redhat.com 2019-10-28 01:26:07 UTC
Test 2 libvirt-5.6.0-7.el8.x86_64 with below 2 scenarios:

1. macvatp:
Create the macvtap device and start vm with it under unprivileged libvirtd:

# ip link add link ens1f1 name mymacvtap0 address 52:54:00:11:11:11  type macvtap mode bridge
# ip link set mymacvtap0 up

$ whoami
yalzhang

$ virsh dumpxml rhel | grep /interface -B5
    <interface type='ethernet'>
      <mac address='52:54:00:11:11:11'/>
      <target dev='mymacvtap0' managed='no'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
    </interface>
$ virsh start rhel
error: Failed to start domain rhel
error: cannot open macvtap tap device /dev/tap11: Permission denied

# chown  yalzhang:yalzhang  /dev/tap11
or 
# chown yalzhang:yalzhang /dev/tap$(ip link show mymacvtap0 | head -1 | cut -d: -f1)

$ virsh start rhel
Domain rhel started

login the guest, guest can get ip address in the same subnet of the host's.
And check the network functions, the network works well.

2. bridge type:
create linux bridge and connect it with the host physical interface, then start vm under unprivileged libvirtd:

# tmux -c "ip link add name br0 type bridge; ip link set ens1f1 up; ip link set ens1f1 master br0; ip link set br0 up; pkill dhclient; dhclient br0"
# ip tuntap add mode tap user yalzhang group yalzhang name mytap0
# ip link set mytap0 up
# ip link set mytap0 master br0

$ whoami
yalzhang

$ virsh dumpxml rhel | grep /interface -B6
    <interface type='ethernet'>
      <mac address='52:54:00:93:0f:bc'/>
      <target dev='mytap0' managed='no'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
    </interface>

$ virsh start rhel
Domain rhel started

login the vm and check network function, it works as expected:
[root@localhost ~]# ifconfig
enp8s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.xx.xx.xx  netmask 255.255.252.0  broadcast 10.xx.xx.xx
        inet6 fe80::78ee:d280:ee35:7ca8  prefixlen 64  scopeid 0x20<link>
        ether 52:54:00:93:0f:bc  txqueuelen 1000  (Ethernet)
...

$ ip a  | grep mytap0 -A3
12: mytap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
    link/ether 16:7b:c1:cc:bb:4f brd ff:ff:ff:ff:ff:ff
    inet6 fe80::147b:c1ff:fecc:bb4f/64 scope link 
       valid_lft forever preferred_lft forever

Test the guest's network function, it works well.

Comment 14 yalzhang@redhat.com 2019-10-28 09:26:16 UTC
Some negative scenarios:

1. managed='no' without specify the target dev:
$ virsh dumpxml rhel | grep /interface -B5
    <interface type='ethernet'>
      <mac address='52:54:00:11:11:12'/>
      <target managed='no'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

$ virsh start rhel
error: Failed to start domain rhel
error: internal error: target dev must be supplied when managed='no'

2. managed='no' + the specified target dev do not exists:
$ ip l | grep vnet0
$ ===> no output

$ virsh dumpxml rhel | grep /interface -B5
    <interface type='ethernet'>
      <mac address='52:54:00:11:11:12'/>
      <target dev='vnet0' managed='no'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

$ virsh start rhel
error: Failed to start domain rhel
error: internal error: target managed='no' but specified dev doesn't exist

3. "managed=yes"
$ virsh dumpxml rhel | grep /interface -B5
    <interface type='ethernet'>
      <mac address='52:54:00:11:11:12'/>
      <target dev='mytap0' managed='yes'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

$ virsh start rhel
error: Failed to start domain rhel
error: Cannot set interface MAC to fe:54:00:11:11:12 on 'mytap0': Operation not permitted

Comment 15 yalzhang@redhat.com 2019-10-28 10:03:41 UTC
Created attachment 1629743 [details]
the coverage report for the patches

Comment 17 errata-xmlrpc 2020-02-04 18:28:48 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2020:0404


Note You need to log in before you can comment on or make changes to this bug.