Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.
RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.

Bug 1422534

Summary: vdev->vq[i].used_idx does not consider the right value for vhostuser
Product: Red Hat Enterprise Linux 7 Reporter: Jaison Raju <jraju>
Component: qemu-kvm-rhevAssignee: Maxime Coquelin <maxime.coquelin>
Status: CLOSED NOTABUG QA Contact: Pei Zhang <pezhang>
Severity: medium Docs Contact:
Priority: high    
Version: 7.2CC: ailan, chayang, chhudson, jasowang, jdonohue, jraju, juzhang, knoel, marcandre.lureau, maxime.coquelin, michen, mst, muraliv, pezhang, pginchev, qding, stefanha, therbert, vaggarwa, virt-bugs, virt-maint, xiywang
Target Milestone: rc   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard: hot
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2017-03-12 21:51:33 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1154739, 1420851    
Attachments:
Description Flags
VPP: Debug patch to avoid vring re-init before saving its last_avail_idx value none

Description Jaison Raju 2017-02-15 13:31:39 UTC
Description of problem:
We notice this discrepancy when vhostuser interface is terminated with FD.IO VPP

The code in QEMU hw/virtio/virtio.c wrongly assumes that vdev->vq[i].used_idx (which is just a cached value of vdev->vq[i].vring.used.idx) is managed exclusively by this code.
This isn't true for vhostuser where the rings are directly manipulated (without the help of virtio.c logic).

What happens is that 'vring.used.idx' has the correct index, vring is part of physical memory that's copied in migration,
On migration load (inside 'virtio_load') used_idx is updated with the actual index value -- from 'vring.used.idx' (normally non-zero, if some packets did pass):
vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]);

But virtio.c logic didn't handle all these packets, so 'vdev->vq[i].last_avail_idx' is still zero, which causes the error and migration abort

Version-Release number of selected component (if applicable):
2.3.0-31.el7_2.21

How reproducible:
Always on customer environment .

Steps to Reproduce:
Customer is using in-house DPDK-based solution .

Actual results:
Instance migration fails

Expected results:
Instance migration succeeds 

Additional info:
This modification was done in the following patch :
QEMU commit-id bccdef6b1a204db0f41ffb6e24ce373e4d7890d4 "virtio: recalculate vq->inuse after migration"
Applied as 'kvm-virtio-recalculate-vq-inuse-after-migration.patch' in:

# For bz#1372763 - RHSA-2016-1756 breaks migration of instances
Patch480: kvm-virtio-recalculate-vq-inuse-after-migration.patch

Backported in qemu in version: 2.3.0-31.el7_2.21

Comment 3 Marc-Andre Lureau 2017-02-17 21:21:44 UTC
It looks like we should remove the check for now. And we may want to teach virtio.c to get the last_avail_idx from vhost during migration. Or to disable the check on vhost (I wonder if this is reproducible with vhost-kernel?). Stefan, any other idea?

Comment 4 Amnon Ilan 2017-02-20 08:38:43 UTC
Can you try reproducing it with the PVP test setup by Maxime?
http://dpdk.org/doc/guides/howto/pvp_reference_benchmark.html?highlight=pvp

This can help since it uses DPDK only (no need for switch like VPP).

Comment 5 jason wang 2017-02-20 09:59:49 UTC
(In reply to Marc-Andre Lureau from comment #3)
> It looks like we should remove the check for now. And we may want to teach
> virtio.c to get the last_avail_idx from vhost during migration. Or to
> disable the check on vhost (I wonder if this is reproducible with
> vhost-kernel?). Stefan, any other idea?

Could it be not a bug of qemu? We should have synced last_avail_idx (GET_VRING_BASE) during device stop on src.

Comment 6 Jaison Raju 2017-02-22 05:03:22 UTC
(In reply to Amnon Ilan from comment #4)
> Can you try reproducing it with the PVP test setup by Maxime?
> http://dpdk.org/doc/guides/howto/pvp_reference_benchmark.html?highlight=pvp
> 
> This can help since it uses DPDK only (no need for switch like VPP).

Hello Peter ,

Can you confirm the test results using the guide provided by engineering ?

Regards,
Jaison R

Comment 7 VIKRANT 2017-02-27 12:32:53 UTC
Here is the response which we got from Cu. on support case.

This issue exists with PVP too, Ideally we need this fixed with FDIO VPP.

Comment 11 Stefan Hajnoczi 2017-02-28 15:49:20 UTC
(In reply to jason wang from comment #5)
> (In reply to Marc-Andre Lureau from comment #3)
> > It looks like we should remove the check for now. And we may want to teach
> > virtio.c to get the last_avail_idx from vhost during migration. Or to
> > disable the check on vhost (I wonder if this is reproducible with
> > vhost-kernel?). Stefan, any other idea?
> 
> Could it be not a bug of qemu? We should have synced last_avail_idx
> (GET_VRING_BASE) during device stop on src.

Yes, the vring state needs to be synced.  This is how vhost kernel and dataplane work, too.

Comment 15 VIKRANT 2017-03-02 08:58:41 UTC
Pei, can you please check with "--live" option are you able to reproduce the issue or not?

~~~
Please note, the problem is migrating live OS values,
Which means you need to perform live migration:
virsh migrate --live
~~~

Comment 16 Pei Zhang 2017-03-02 09:35:32 UTC
(In reply to VIKRANT from comment #15)
> Pei, can you please check with "--live" option are you able to reproduce the
> issue or not?
> 
> ~~~
> Please note, the problem is migrating live OS values,
> Which means you need to perform live migration:
> virsh migrate --live
> ~~~

Hi Vikrant, still works well, can not reproduce.

[root@dell-per430-10 ~]# virsh migrate --verbose --persistent --live rhel7.3 qemu+ssh://10.73.73.67/system 
Migration: [100 %]

[root@dell-per430-11 ~]# virsh migrate --verbose --persistent --live rhel7.3 qemu+ssh://10.73.73.65/system
Migration: [100 %]

[root@dell-per430-10 ~]# virsh migrate --verbose --undefinesource --live rhel7.3 qemu+ssh://10.73.73.67/system 
Migration: [100 %]

[root@dell-per430-11 ~]# virsh migrate --verbose --undefinesource --live rhel7.3 qemu+ssh://10.73.73.65/system
Migration: [100 %]

Thanks,
Pei

Comment 17 VIKRANT 2017-03-03 03:37:48 UTC
Hi Pei,

Can you please share the output of  following command.

# virsh domiflist rhel7.3

Comment 18 Pei Zhang 2017-03-03 04:50:48 UTC
(In reply to VIKRANT from comment #17)
> Hi Pei,
> 
> Can you please share the output of  following command.
> 
> # virsh domiflist rhel7.3

Vikrant, please see below:

# virsh domiflist rhel7.3
Interface  Type       Source     Model       MAC
-------------------------------------------------------
vnet0      bridge     switch     virtio      fa:5e:07:b4:08:91
-          vhostuser  -          virtio      fa:5e:07:b4:08:92
-          vhostuser  -          virtio      fa:5e:07:b4:08:93

XML info:
# cat rhel7.3.xml 
<domain type='kvm'>
  <name>rhel7.3</name>
  <uuid>c52b047f-68a3-4a0d-b34f-e8596977064e</uuid>
  <memory unit='KiB'>8388608</memory>
  <currentMemory unit='KiB'>8388608</currentMemory>
  <memoryBacking>
    <hugepages>
      <page size='1048576' unit='KiB' nodeset='0'/>
    </hugepages>
    <locked/>
  </memoryBacking>
  <vcpu placement='static'>4</vcpu>
  <cputune>
    <vcpupin vcpu='0' cpuset='12'/>
    <vcpupin vcpu='1' cpuset='14'/>
    <vcpupin vcpu='2' cpuset='16'/>
    <vcpupin vcpu='3' cpuset='18'/>
    <emulatorpin cpuset='1,3,5,7,9'/>
  </cputune>
  <numatune>
    <memory mode='strict' nodeset='0'/>
  </numatune>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='hd'/>
  </os>
  <cpu mode='host-passthrough'>
    <feature policy='require' name='tsc-deadline'/>
    <numa>
      <cell id='0' cpus='0-3' memory='8388608' unit='KiB' memAccess='shared'/>
    </numa>
  </cpu>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none' io='threads'/>
      <source file='/mnt/nfv/rhel7.3.qcow2'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='none'/>
    <controller type='pci' index='0' model='pci-root'/>

    <interface type='bridge'>
      <mac address='fa:5e:07:b4:08:91'/>
      <source bridge='switch'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </interface>
    <interface type='vhostuser'>
      <mac address='fa:5e:07:b4:08:92'/>
      <source type='unix' path='/tmp/vhost-user1' mode='client'/>
      <model type='virtio'/>
      <driver name='vhost' rx_queue_size='256' />
      <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/>
    </interface>
    <interface type='vhostuser'>
      <mac address='fa:5e:07:b4:08:93'/>
      <source type='unix' path='/tmp/vhost-user2' mode='client'/>
      <model type='virtio'/>
      <driver name='vhost' rx_queue_size='256' />
      <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/>
    </interface>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
    </memballoon>
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
  </devices>
</domain>



Best Regards,
Pei

Comment 21 m v 2017-03-07 01:39:45 UTC
It seems we have two things that we need to move forward on.

Now, you could add the 2 host VPP setup to do your own repro or jump on our TB to see the problem themselves. As discussed in the very first comment on this bug, it's the way that FD.io's vhostuser driver works that triggers the ringbuffer handling problem in QEMU, so if you haven't been using the FD.io vhostuser driver you probably haven't triggered the exact issue.

Your engineers immediately seem to have seen the problem (with ringbuffer indexes) and suggest that it is an obvious problem with QEMU and a straightforward fix.  Can you please share your fix for that, and we can run it in our testbed and report back?

Can you suggest how to move forward on these two points?  As you can see, we can do either of them independently.  We would like an urgent resolution to this issue so let's progress both.

Comment 24 Maxime Coquelin 2017-03-07 13:03:51 UTC
As the problem is not reproducible with DPDK or OVS-DPDK on Pei setup, I had a look at VPP's vhost-user implementation.

I found an issue in VPP code, that would explain faced behaviour.
As mentioned by Jason in Comment 5, Qemu requests last_avail_idx to vhost-user backend using GET_VRING_BASE.

In VPP, this is implemented as follow:

static clib_error_t *
vhost_user_socket_read (unix_file_t * uf)
{
...
  switch (msg.request)
    {
...
    case VHOST_USER_GET_VRING_BASE:
      DBG_SOCK ("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
		vui->hw_if_index, msg.state.index, msg.state.num);

      if (msg.state.index >= VHOST_VRING_MAX_N)
	{
	  DBG_SOCK ("invalid vring index VHOST_USER_GET_VRING_BASE:"
		    " %d >= %d", msg.state.index, VHOST_VRING_MAX_N);
	  goto close_socket;
	}

      /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
      vhost_user_vring_close (vui, msg.state.index);

      msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
      msg.flags |= 4;
      msg.size = sizeof (msg.state);
      break;
...
}

As the comment says, the vq must be stopped before getting the index,
so VPP calls vhost_user_vring_close()

The problem is that this vhost_user_vring_close() function calls vhost_user_vring_init(),
which resets the vhost_user_vring_t struct to zeros.

Since vhost_user_vring_t stores the index, the index gets cleared before being read.

Solution I think is to close the device without re-initializing it.

Comment 25 Tom Herbert 2017-03-07 22:23:55 UTC
Maxime,
Could you add include the commit or version of VPP?

Comment 26 Tom Herbert 2017-03-07 23:31:03 UTC
It looks like you have access to the source above. Try typing from the top vpp directory
build-root/scripts/version

That worked back to the 16.06 release.

Comment 27 Maxime Coquelin 2017-03-08 08:56:49 UTC
Tom,

I had a look at mainline VPP:
$ build-root/scripts/version
17.04-rc0~382-ga0b34a7

Looking at 16.06 release, it seems to be a regression, as the vring struct is not reset before getting last_avail_idx, only the enable bit is cleared:

    case VHOST_USER_GET_VRING_BASE:
      DBG_SOCK("if %d msg VHOST_USER_GET_VRING_BASE idx %d num %d",
        vui->hw_if_index, msg.state.index, msg.state.num);

      /* Spec says: Client must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE. */
      vui->vrings[msg.state.index].enabled = 0;

      msg.state.num = vui->vrings[msg.state.index].last_avail_idx;
      msg.flags |= 4;
      msg.size = sizeof(msg.state);
      break;

The regression seems to have been introduced by below commit, which landed into v17.01 release:

$  git blame src/vnet/devices/virtio/vhost-user.c -L 1031
e21c5286 vnet/vnet/devices/virtio/vhost-user.c (Pierre Pfister     2016-09-21 08:04:59 +0100 1031)       vhost_user_vring_close (vui, msg.state.index);

$ git show e21c5286
commit e21c52861d7c503bef7fc464f23bbc7891e150d7
Author: Pierre Pfister <ppfister>
Date:   Wed Sep 21 08:04:59 2016 +0100

    vhost-user: multiqueue support
    
    This patch adds multi-queue support to non-dpdk's vhost-user
    driver.
    Waiting for a unified way to manage threads, this patch
    defines a way to assign threads to interfaces that is
    specific to vhost.
    
    Change-Id: I86298788b1a4e886c5431f187dc17175d12c7a8b
    Signed-off-by: Pierre Pfister <ppfister>

$ git tag --contains e21c5286
v17.01
v17.01-rc1
v17.01-rc2
v17.01.1
v17.04-rc0
We should invite Pierre Pfister from Cisco in the discussion,
as he might have some ideas on the fix to do.

I guess that reverting to just clearing the enabled bit is not the right fix.
Maybe the vring struct shouldn't be re-initialized in the close function,
but should be called directly when needed.

I'm attaching a debug patch to confirm the root cause if someone want to have a try.
It is not intended to be the fix for this issue, and has not neither been compiled nor tested.

Regards,
Maxime

Comment 28 Maxime Coquelin 2017-03-08 08:58:14 UTC
Created attachment 1261140 [details]
VPP: Debug patch to avoid vring re-init before saving its last_avail_idx value

Comment 29 Peter Ginchev 2017-03-08 09:26:58 UTC
I've checked the suggested patch and it fixes the migration problem

Comment 30 Maxime Coquelin 2017-03-08 12:33:33 UTC
Thanks for testing Peter.
I invited Pierre Pfister to comment on this ticket,
he's the best placed to provide the final fix.

Regards,
Maxime

Comment 33 VIKRANT 2017-03-10 06:23:38 UTC
As per confirmation from Peter. We are good to close this bug.

Once again many thanks guys for quick inputs on this bug.

Comment 35 Peter Ginchev 2017-03-16 08:57:59 UTC
VPP fix was done in:
http://gerrit.fd.io/r/#/c/5700

Comment 36 Maxime Coquelin 2017-03-16 09:05:53 UTC
Peter, Steven,

Not sure about the fix.
Shouldn't the vring be stopped before saving the last_avail_idx value?

Regards,
Maxime

Comment 37 Peter Ginchev 2017-03-16 09:10:37 UTC
Hi Maxime,

The whole logic of 'vhost_user_socket_read' function is kept between 'vlib_worker_thread_barrier_sync' and 'vlib_worker_thread_barrier_release', which implements holding all worker threads, so no packets will be processed at that time.
So this simpler fix is fine.

Cheers,
Peter

Comment 38 Maxime Coquelin 2017-03-16 09:16:56 UTC
Ok Peter, thanks for the explanation. You can forget my comment.

I don't know much about VPP internals, but wanted to be sure it was taken into account.

Regards,
Maxime

Comment 39 Amnon Ilan 2017-03-16 10:51:43 UTC
And just one general comment:
Moving forward, we should see how to convert VPP to use the 
vhost-user from DPDK library.

Comment 40 Tom Herbert 2017-03-16 12:50:17 UTC
Yes, that was our intention in the VPP community before 1611 release. Its time for re-syncing on the issues and the LOE for use of dpdk vhost-user moving forward.