提交 9a081683 编写于 作者: L Laine Stump

util: restructure virNetDevReadNetConfig() to eliminate false error logs

virHostdevRestoreNetConfig() calls virNetDevReadNetConfig() to try and
read the "original config" of a netdev, and if that fails, it tries
again with a different directory/netdev name. This achieves the
desired effect (we end up finding the config wherever it may be), but
for each failure, virNetDevReadNetConfig() places a nice error message
in the system logs. Experience has shown that false-positive error
logs like this lead to erroneous bug reports, and can often mislead
those searching for *real* bugs.

This patch changes virNetDevReadNetConfig() to explicitly check if the
file exists before calling virFileReadAll(); if it doesn't exist,
virNetDevReadNetConfig() returns a success, but leaves all the
variables holding the results as NULL. (This makes sense if you define
the purpose of the function as "read a netdev's config from its config
file *if that file exists*).

To take advantage of that change, the caller,
virHostdevRestoreNetConfig() is modified to fail immediately if
virNetDevReadNetConfig() returns an error, and otherwise to try the
different directory/netdev name if adminMAC & vlan & MAC are all NULL
after the preceding attempt.
上级 b67eaa63
...@@ -534,6 +534,10 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev, ...@@ -534,6 +534,10 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
int ret = -1; int ret = -1;
int vf = -1; int vf = -1;
bool port_profile_associate = false; bool port_profile_associate = false;
virMacAddrPtr MAC = NULL;
virMacAddrPtr adminMAC = NULL;
virNetDevVlanPtr vlan = NULL;
/* This is only needed for PCI devices that have been defined /* This is only needed for PCI devices that have been defined
* using <interface type='hostdev'>. For all others, it is a NOP. * using <interface type='hostdev'>. For all others, it is a NOP.
...@@ -559,62 +563,92 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev, ...@@ -559,62 +563,92 @@ virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
NULL, NULL,
port_profile_associate); port_profile_associate);
} else { } else {
virMacAddrPtr MAC = NULL; /* we need to try 3 different places for the config file:
virMacAddrPtr adminMAC = NULL; * 1) ${stateDir}/${PF}_vf${vf}
virNetDevVlanPtr vlan = NULL; * This is almost always where the saved config is
*
ret = virNetDevReadNetConfig(linkdev, vf, stateDir, &adminMAC, &vlan, &MAC); * 2) ${oldStateDir/${PF}_vf${vf}
if (ret < 0 && oldStateDir) * saved config is only here if this machine was running a
ret = virNetDevReadNetConfig(linkdev, vf, oldStateDir, * (by now *very*) old version of libvirt that saved the
&adminMAC, &vlan, &MAC); * file in a different directory
*
if (ret < 0) { * 3) ${stateDir}${PF[1]}_vf${VF}
/* see if the config was saved using the PF's "port 2" * PF[1] means "the netdev for port 2 of the PF device", and
* netdev for the file name. * is only valid when the PF is a Mellanox dual port NIC with
*/ * a VF that was created in "single port" mode.
VIR_FREE(linkdev); *
* NB: if virNetDevReadNetConfig() returns < 0, then it found
* the file, but there was a problem, so we should
* immediately return an error to our caller. If it returns
* 0, but all of the interesting stuff is NULL, that means
* the file wasn't found, so we can/should check other
* locations for it.
*/
if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) >= 0) { /* 1) standard location */
ret = virNetDevReadNetConfig(linkdev, vf, stateDir, if (virNetDevReadNetConfig(linkdev, vf, stateDir,
&adminMAC, &vlan, &MAC); &adminMAC, &vlan, &MAC) < 0) {
} goto cleanup;
} }
if (ret == 0) { /* 2) "old" (pre-1.2.3 circa 2014) location - whenever we get
/* if a MAC was stored for the VF, we should now restore * to the point that nobody will ever upgrade directly from
* that as the adminMAC. We have to do it this way because * 1.2.3 (or older) directly to current libvirt, we can
* the VF is still not bound to the host's net driver, so * eliminate this clause
* we can't directly set its MAC (and even after it is **/
* re-bound to the host net driver, it will still have its if (!(adminMAC || vlan || MAC) && oldStateDir &&
* "administratively set" flag on, and that prohibits the virNetDevReadNetConfig(linkdev, vf, oldStateDir,
* VF's net driver from directly setting the MAC &adminMAC, &vlan, &MAC) < 0) {
* anyway). But it we set the desired VF MAC as the "admin goto cleanup;
* MAC" *now*, then when the VF is re-bound to the host }
* net driver (which will happen soon after returning from
* this function), that adminMAC will be set (by the PF) /* 3) try using the PF's "port 2" netdev as the name of the
* as the VF's new initial MAC. * config file
* */
* If no MAC was stored for the VF, that means it wasn't if (!(adminMAC || vlan || MAC)) {
* bound to a net driver before we used it anyway, so the VIR_FREE(linkdev);
* adminMAC is all we have, and we can just restore it
* directly. if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) < 0 ||
*/ virNetDevReadNetConfig(linkdev, vf, stateDir,
if (MAC) { &adminMAC, &vlan, &MAC) < 0) {
VIR_FREE(adminMAC); goto cleanup;
adminMAC = MAC;
MAC = NULL;
} }
}
ignore_value(virNetDevSetNetConfig(linkdev, vf, /* if a MAC was stored for the VF, we should now restore
adminMAC, vlan, MAC, true)); * that as the adminMAC. We have to do it this way because
* the VF is still not bound to the host's net driver, so
* we can't directly set its MAC (and even after it is
* re-bound to the host net driver, it will still have its
* "administratively set" flag on, and that prohibits the
* VF's net driver from directly setting the MAC
* anyway). But it we set the desired VF MAC as the "admin
* MAC" *now*, then when the VF is re-bound to the host
* net driver (which will happen soon after returning from
* this function), that adminMAC will be set (by the PF)
* as the VF's new initial MAC.
*
* If no MAC was stored for the VF, that means it wasn't
* bound to a net driver before we used it anyway, so the
* adminMAC is all we have, and we can just restore it
* directly.
*/
if (MAC) {
VIR_FREE(adminMAC);
adminMAC = MAC;
MAC = NULL;
} }
VIR_FREE(MAC); ignore_value(virNetDevSetNetConfig(linkdev, vf,
VIR_FREE(adminMAC); adminMAC, vlan, MAC, true));
virNetDevVlanFree(vlan);
} }
ret = 0;
cleanup:
VIR_FREE(linkdev); VIR_FREE(linkdev);
VIR_FREE(MAC);
VIR_FREE(adminMAC);
virNetDevVlanFree(vlan);
return ret; return ret;
} }
......
...@@ -1971,7 +1971,9 @@ virNetDevSaveNetConfig(const char *linkdev, int vf, ...@@ -1971,7 +1971,9 @@ virNetDevSaveNetConfig(const char *linkdev, int vf,
* @linkdev:@vf from a file in @stateDir. (see virNetDevSaveNetConfig * @linkdev:@vf from a file in @stateDir. (see virNetDevSaveNetConfig
* for details of file name and format). * for details of file name and format).
* *
* Returns 0 on success, -1 on failure. * Returns 0 on success, -1 on failure. It is *NOT* considered failure
* if no file is found to read. In that case, adminMAC, vlan, and MAC
* are set to NULL, and success is returned.
* *
* The caller MUST free adminMAC, vlan, and MAC when it is finished * The caller MUST free adminMAC, vlan, and MAC when it is finished
* with them (they will be NULL if they weren't found in the file) * with them (they will be NULL if they weren't found in the file)
...@@ -2036,8 +2038,8 @@ virNetDevReadNetConfig(const char *linkdev, int vf, ...@@ -2036,8 +2038,8 @@ virNetDevReadNetConfig(const char *linkdev, int vf,
if (linkdev && !virFileExists(filePath)) { if (linkdev && !virFileExists(filePath)) {
/* the device may have been stored in a file named for the /* the device may have been stored in a file named for the
* VF due to saveVlan == false (or an older version of * VF due to saveVlan == false (or an older version of
* libvirt), so reset filePath so we'll try the other * libvirt), so reset filePath and pfDevName so we'll try
* filename before failing. * the other filename.
*/ */
VIR_FREE(filePath); VIR_FREE(filePath);
pfDevName = NULL; pfDevName = NULL;
...@@ -2049,6 +2051,14 @@ virNetDevReadNetConfig(const char *linkdev, int vf, ...@@ -2049,6 +2051,14 @@ virNetDevReadNetConfig(const char *linkdev, int vf,
goto cleanup; goto cleanup;
} }
if (!virFileExists(filePath)) {
/* having no file to read is not necessarily an error, so we
* just return success, but with MAC, adminMAC, and vlan set to NULL
*/
ret = 0;
goto cleanup;
}
if (virFileReadAll(filePath, 128, &fileStr) < 0) if (virFileReadAll(filePath, 128, &fileStr) < 0)
goto cleanup; goto cleanup;
......
...@@ -1187,8 +1187,9 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname, ...@@ -1187,8 +1187,9 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
virMacAddrPtr adminMAC = NULL; virMacAddrPtr adminMAC = NULL;
virNetDevVlanPtr vlan = NULL; virNetDevVlanPtr vlan = NULL;
if (virNetDevReadNetConfig(linkdev, -1, stateDir, if ((virNetDevReadNetConfig(linkdev, -1, stateDir,
&adminMAC, &vlan, &MAC) == 0) { &adminMAC, &vlan, &MAC) == 0) &&
(adminMAC || vlan || MAC)) {
ignore_value(virNetDevSetNetConfig(linkdev, -1, ignore_value(virNetDevSetNetConfig(linkdev, -1,
adminMAC, vlan, MAC, !!vlan)); adminMAC, vlan, MAC, !!vlan));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册