Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
/*
|
2016-01-08 19:09:31 +00:00
|
|
|
* Copyright (C) 2009-2016 Red Hat, Inc.
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virnetdevvportprofile.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NET
|
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virNetDevVPort,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LAST,
|
2013-10-10 15:41:05 +00:00
|
|
|
"none",
|
|
|
|
"802.1Qbg",
|
|
|
|
"802.1Qbh",
|
2015-02-23 20:54:54 +00:00
|
|
|
"openvswitch",
|
2019-01-20 16:30:15 +00:00
|
|
|
"midonet",
|
|
|
|
);
|
2013-10-10 15:41:05 +00:00
|
|
|
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virNetDevVPortProfileOp,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_OP_LAST,
|
2011-11-02 17:11:02 +00:00
|
|
|
"create",
|
|
|
|
"save",
|
|
|
|
"restore",
|
|
|
|
"destroy",
|
|
|
|
"migrate out",
|
|
|
|
"migrate in start",
|
|
|
|
"migrate in finish",
|
2019-01-20 16:30:15 +00:00
|
|
|
"no-op",
|
|
|
|
);
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2020-09-28 21:39:46 +00:00
|
|
|
#if defined(WITH_LIBNL)
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
# include <fcntl.h>
|
|
|
|
|
2013-06-13 06:26:22 +00:00
|
|
|
# include <net/if.h>
|
2011-11-02 17:11:02 +00:00
|
|
|
# include <linux/if_tun.h>
|
|
|
|
|
2012-02-03 14:13:19 +00:00
|
|
|
# include "virnetlink.h"
|
2011-11-02 17:11:02 +00:00
|
|
|
# include "virfile.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
# include "virlog.h"
|
2011-11-02 17:11:02 +00:00
|
|
|
# include "virnetdev.h"
|
2020-01-14 17:38:59 +00:00
|
|
|
# include "virsocket.h"
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.netdevvportprofile");
|
|
|
|
|
2011-11-02 17:11:02 +00:00
|
|
|
# define MICROSEC_PER_SEC (1000 * 1000)
|
|
|
|
|
|
|
|
# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC)
|
|
|
|
# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8)
|
|
|
|
|
|
|
|
# define LLDPAD_PID_FILE "/var/run/lldpad.pid"
|
|
|
|
|
|
|
|
|
|
|
|
enum virNetDevVPortProfileLinkOp {
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE = 0x1,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE = 0x2,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE = 0x3,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR = 0x4,
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
|
|
|
|
bool
|
2019-10-01 17:56:35 +00:00
|
|
|
virNetDevVPortProfileEqual(const virNetDevVPortProfile *a, const virNetDevVPortProfile *b)
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
{
|
|
|
|
/* NULL resistant */
|
|
|
|
if (!a && !b)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!a || !b)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (a->virtPortType != b->virtPortType)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (a->virtPortType) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_NONE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
2012-07-25 01:14:41 +00:00
|
|
|
if (a->managerID != b->managerID ||
|
|
|
|
a->typeID != b->typeID ||
|
|
|
|
a->typeIDVersion != b->typeIDVersion ||
|
|
|
|
memcmp(a->instanceID, b->instanceID, VIR_UUID_BUFLEN) != 0)
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
2012-07-25 01:14:41 +00:00
|
|
|
if (STRNEQ(a->profileID, b->profileID))
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
|
2012-07-25 05:52:32 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
|
|
|
if (STRNEQ(a->profileID, b->profileID) ||
|
|
|
|
memcmp(a->interfaceID, b->interfaceID, VIR_UUID_BUFLEN) != 0)
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
|
Split src/util/network.{c,h} into 5 pieces
The src/util/network.c file is a dumping ground for many different
APIs. Split it up into 5 pieces, along functional lines
- src/util/virnetdevbandwidth.c: virNetDevBandwidth type & helper APIs
- src/util/virnetdevvportprofile.c: virNetDevVPortProfile type & helper APIs
- src/util/virsocketaddr.c: virSocketAddr and APIs
- src/conf/netdev_bandwidth_conf.c: XML parsing / formatting
for virNetDevBandwidth
- src/conf/netdev_vport_profile_conf.c: XML parsing / formatting
for virNetDevVPortProfile
* src/util/network.c, src/util/network.h: Split into 5 pieces
* src/conf/netdev_bandwidth_conf.c, src/conf/netdev_bandwidth_conf.h,
src/conf/netdev_vport_profile_conf.c, src/conf/netdev_vport_profile_conf.h,
src/util/virnetdevbandwidth.c, src/util/virnetdevbandwidth.h,
src/util/virnetdevvportprofile.c, src/util/virnetdevvportprofile.h,
src/util/virsocketaddr.c, src/util/virsocketaddr.h: New pieces
* daemon/libvirtd.h, daemon/remote.c, src/conf/domain_conf.c,
src/conf/domain_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/conf/nwfilter_conf.h,
src/esx/esx_util.h, src/network/bridge_driver.c,
src/qemu/qemu_conf.c, src/rpc/virnetsocket.c,
src/rpc/virnetsocket.h, src/util/dnsmasq.h, src/util/interface.h,
src/util/iptables.h, src/util/macvtap.c, src/util/macvtap.h,
src/util/virnetdev.h, src/util/virnetdevtap.c,
tools/virsh.c: Update include files
2011-11-02 15:40:08 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2018-09-03 16:02:35 +00:00
|
|
|
|
|
|
|
int virNetDevVPortProfileCopy(virNetDevVPortProfilePtr *dst, const virNetDevVPortProfile *src)
|
|
|
|
{
|
|
|
|
if (!src) {
|
|
|
|
*dst = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(*dst) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memcpy(*dst, src, sizeof(*src));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-04 07:09:47 +00:00
|
|
|
/* virNetDevVPortProfileCheckComplete() checks that all attributes
|
|
|
|
* required for the type of virtport are specified. When
|
|
|
|
* generateMissing is true, any missing attribute that can be
|
|
|
|
* autogenerated, will be (instanceid, interfaceid). If virtport ==
|
|
|
|
* NULL or virtPortType == NONE, then the result is always 0
|
|
|
|
* (success). If a required attribute is missing, an error is logged
|
|
|
|
* and -1 is returned.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevVPortProfileCheckComplete(virNetDevVPortProfilePtr virtport,
|
|
|
|
bool generateMissing)
|
|
|
|
{
|
|
|
|
const char *missing = NULL;
|
|
|
|
|
|
|
|
if (!virtport || virtport->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (virtport->virtPortType) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
|
|
|
if (!virtport->managerID_specified) {
|
|
|
|
missing = "managerid";
|
|
|
|
} else if (!virtport->typeID_specified) {
|
|
|
|
missing = "typeid";
|
|
|
|
} else if (!virtport->typeIDVersion_specified) {
|
|
|
|
missing = "typeidversion";
|
|
|
|
} else if (!virtport->instanceID_specified) {
|
|
|
|
if (generateMissing) {
|
|
|
|
if (virUUIDGenerate(virtport->instanceID) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot generate a random uuid for instanceid"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virtport->instanceID_specified = true;
|
|
|
|
} else {
|
|
|
|
missing = "instanceid";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
|
|
|
if (!virtport->profileID[0])
|
|
|
|
missing = "profileid";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
|
|
|
/* profileid is optional for openvswitch */
|
|
|
|
if (!virtport->interfaceID_specified) {
|
|
|
|
if (generateMissing) {
|
|
|
|
if (virUUIDGenerate(virtport->interfaceID) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot generate a random uuid for interfaceid"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virtport->interfaceID_specified = true;
|
|
|
|
} else {
|
|
|
|
missing = "interfaceid";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-02-23 20:54:55 +00:00
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_MIDONET:
|
|
|
|
if (!virtport->interfaceID_specified)
|
|
|
|
missing = "interfaceid";
|
|
|
|
break;
|
2012-08-04 07:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (missing) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("missing %s in <virtualport type='%s'>"), missing,
|
|
|
|
virNetDevVPortTypeToString(virtport->virtPortType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virNetDevVPortProfileCheckNoExtras() checks that there are no
|
|
|
|
* attributes specified in this virtport that are inappropriate for
|
|
|
|
* the type. if virtport == NULL or virtPortType == NONE, then the
|
|
|
|
* result is always 0 (success). If an extra attribute is present,
|
|
|
|
* an error is logged and -1 is returned.
|
|
|
|
*/
|
|
|
|
int
|
2019-10-01 17:56:35 +00:00
|
|
|
virNetDevVPortProfileCheckNoExtras(const virNetDevVPortProfile *virtport)
|
2012-08-04 07:09:47 +00:00
|
|
|
{
|
|
|
|
const char *extra = NULL;
|
|
|
|
|
|
|
|
if (!virtport || virtport->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (virtport->virtPortType) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
|
|
|
if (virtport->profileID[0])
|
|
|
|
extra = "profileid";
|
|
|
|
else if (virtport->interfaceID_specified)
|
|
|
|
extra = "interfaceid";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
|
|
|
if (virtport->managerID_specified)
|
|
|
|
extra = "managerid";
|
|
|
|
else if (virtport->typeID_specified)
|
|
|
|
extra = "typeid";
|
|
|
|
else if (virtport->typeIDVersion_specified)
|
|
|
|
extra = "typeidversion";
|
|
|
|
else if (virtport->instanceID_specified)
|
|
|
|
extra = "instanceid";
|
|
|
|
else if (virtport->interfaceID_specified)
|
|
|
|
extra = "interfaceid";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
|
|
|
if (virtport->managerID_specified)
|
|
|
|
extra = "managerid";
|
|
|
|
else if (virtport->typeID_specified)
|
|
|
|
extra = "typeid";
|
|
|
|
else if (virtport->typeIDVersion_specified)
|
|
|
|
extra = "typeidversion";
|
|
|
|
else if (virtport->instanceID_specified)
|
|
|
|
extra = "instanceid";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extra) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("extra %s unsupported in <virtualport type='%s'>"),
|
|
|
|
extra,
|
|
|
|
virNetDevVPortTypeToString(virtport->virtPortType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virNetDevVPortProfileMerge() - merge the attributes in mods into
|
|
|
|
* orig. If anything that is set in mods has already been set in orig
|
|
|
|
* *and doesn't match*, log an error and return -1, otherwise return 0.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileMerge(virNetDevVPortProfilePtr orig,
|
2019-10-01 17:56:35 +00:00
|
|
|
const virNetDevVPortProfile *mods)
|
2012-08-04 07:09:47 +00:00
|
|
|
{
|
|
|
|
enum virNetDevVPortProfile otype;
|
|
|
|
|
|
|
|
if (!orig || !mods)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
otype = orig->virtPortType;
|
|
|
|
|
|
|
|
if (mods->virtPortType != VIR_NETDEV_VPORT_PROFILE_NONE) {
|
|
|
|
if (otype != VIR_NETDEV_VPORT_PROFILE_NONE &&
|
|
|
|
otype != mods->virtPortType) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports "
|
|
|
|
"with mismatched types (%s and %s)"),
|
|
|
|
virNetDevVPortTypeToString(otype),
|
|
|
|
virNetDevVPortTypeToString(mods->virtPortType));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
otype = orig->virtPortType = mods->virtPortType;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->managerID_specified &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->managerID_specified &&
|
|
|
|
(orig->managerID != mods->managerID)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports "
|
|
|
|
"with mismatched managerids (%d and %d)"),
|
|
|
|
orig->managerID, mods->managerID);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
orig->managerID = mods->managerID;
|
|
|
|
orig->managerID_specified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->typeID_specified &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->typeID_specified &&
|
|
|
|
(orig->typeID != mods->typeID)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports "
|
|
|
|
"with mismatched typeids (%d and %d)"),
|
|
|
|
orig->typeID, mods->typeID);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
orig->typeID = mods->typeID;
|
|
|
|
orig->typeID_specified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->typeIDVersion_specified &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->typeIDVersion_specified &&
|
|
|
|
(orig->typeIDVersion != mods->typeIDVersion)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports with "
|
|
|
|
"mismatched typeidversions (%d and %d)"),
|
|
|
|
orig->typeIDVersion, mods->typeIDVersion);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
orig->typeIDVersion = mods->typeIDVersion;
|
|
|
|
orig->typeIDVersion_specified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->instanceID_specified &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_8021QBG ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->instanceID_specified &&
|
|
|
|
memcmp(orig->instanceID, mods->instanceID,
|
|
|
|
sizeof(orig->instanceID))) {
|
|
|
|
char origuuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char modsuuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports with "
|
|
|
|
"mismatched instanceids ('%s' and '%s')"),
|
|
|
|
virUUIDFormat(orig->instanceID, origuuid),
|
|
|
|
virUUIDFormat(mods->instanceID, modsuuid));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(orig->instanceID, mods->instanceID, sizeof(orig->instanceID));
|
|
|
|
orig->instanceID_specified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->interfaceID_specified &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->interfaceID_specified &&
|
|
|
|
memcmp(orig->interfaceID, mods->interfaceID,
|
|
|
|
sizeof(orig->interfaceID))) {
|
|
|
|
char origuuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char modsuuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports with "
|
|
|
|
"mismatched interfaceids ('%s' and '%s')"),
|
|
|
|
virUUIDFormat(orig->interfaceID, origuuid),
|
|
|
|
virUUIDFormat(mods->interfaceID, modsuuid));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(orig->interfaceID, mods->interfaceID, sizeof(orig->interfaceID));
|
|
|
|
orig->interfaceID_specified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mods->profileID[0] &&
|
|
|
|
(otype == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_8021QBH ||
|
|
|
|
otype == VIR_NETDEV_VPORT_PROFILE_NONE)) {
|
|
|
|
if (orig->profileID[0] &&
|
|
|
|
STRNEQ(orig->profileID, mods->profileID)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("attempt to merge virtualports with "
|
|
|
|
"mismatched profileids ('%s' and '%s')"),
|
|
|
|
orig->profileID, mods->profileID);
|
|
|
|
return -1;
|
|
|
|
}
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(orig->profileID, mods->profileID) < 0) {
|
2012-08-04 07:09:47 +00:00
|
|
|
/* this should never happen - it indicates mods->profileID
|
|
|
|
* isn't properly null terminated. */
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("corrupted profileid string"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* virNetDevVPortProfileMerge3() - create a new virNetDevVPortProfile
|
|
|
|
* that is a combination of the three input profiles. fromInterface is
|
|
|
|
* highest priority and fromPortgroup is lowest. As lower priority
|
|
|
|
* objects' attributes are merged in, if the attribute is unset in the
|
|
|
|
* result object, it is set from the lower priority object, but if it
|
|
|
|
* is already set in the result and the lower priority object wants to
|
|
|
|
* change it, that is an error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int virNetDevVPortProfileMerge3(virNetDevVPortProfilePtr *result,
|
2019-10-01 17:56:35 +00:00
|
|
|
const virNetDevVPortProfile *fromInterface,
|
|
|
|
const virNetDevVPortProfile *fromNetwork,
|
|
|
|
const virNetDevVPortProfile *fromPortgroup)
|
2012-08-04 07:09:47 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
*result = NULL;
|
|
|
|
|
|
|
|
if ((!fromInterface || (fromInterface->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)) &&
|
|
|
|
(!fromNetwork || (fromNetwork->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE)) &&
|
|
|
|
(!fromPortgroup || (fromPortgroup->virtPortType == VIR_NETDEV_VPORT_PROFILE_NONE))) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* at least one of the source profiles is non-empty */
|
2013-07-04 10:17:18 +00:00
|
|
|
if (VIR_ALLOC(*result) < 0)
|
2012-08-04 07:09:47 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* start with the interface's profile. There are no pointers in a
|
|
|
|
* virtualPortProfile, so a shallow copy is sufficient.
|
|
|
|
*/
|
|
|
|
if (fromInterface)
|
|
|
|
**result = *fromInterface;
|
|
|
|
|
|
|
|
if (virNetDevVPortProfileMerge(*result, fromNetwork) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virNetDevVPortProfileMerge(*result, fromPortgroup) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
error:
|
2012-08-04 07:09:47 +00:00
|
|
|
if (ret < 0)
|
|
|
|
VIR_FREE(*result);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2020-09-28 21:39:46 +00:00
|
|
|
#if defined(WITH_LIBNL)
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
|
|
|
|
{
|
2018-09-13 08:55:20 +00:00
|
|
|
[IFLA_PORT_RESPONSE] = { .type = NLA_U16 },
|
2011-11-02 17:11:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static uint32_t
|
2014-03-18 08:14:35 +00:00
|
|
|
virNetDevVPortProfileGetLldpadPid(void)
|
|
|
|
{
|
2011-11-02 17:11:02 +00:00
|
|
|
int fd;
|
|
|
|
uint32_t pid = 0;
|
|
|
|
|
|
|
|
fd = open(LLDPAD_PID_FILE, O_RDONLY);
|
|
|
|
if (fd >= 0) {
|
|
|
|
char buffer[10];
|
|
|
|
|
|
|
|
if (saferead(fd, buffer, sizeof(buffer)) <= sizeof(buffer)) {
|
|
|
|
unsigned int res;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
if (virStrToLong_ui(buffer, &endptr, 10, &res) == 0
|
2019-11-18 14:10:02 +00:00
|
|
|
&& (*endptr == '\0' || g_ascii_isspace(*endptr))
|
2011-11-02 17:11:02 +00:00
|
|
|
&& res != 0) {
|
|
|
|
pid = res;
|
|
|
|
} else {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-02 17:11:02 +00:00
|
|
|
_("error parsing pid of lldpad"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Error opening file %s"), LLDPAD_PID_FILE);
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevVPortProfileGetStatus:
|
|
|
|
*
|
|
|
|
* tb: top level netlink response attributes + values
|
|
|
|
* vf: The virtual function used in the request
|
|
|
|
* instanceId: instanceId of the interface (vm uuid in case of 802.1Qbh)
|
|
|
|
* is8021Qbg: whether this function is call for 8021Qbg
|
|
|
|
* status: pointer to a uint16 where the status will be written into
|
|
|
|
*
|
|
|
|
* Get the status from the IFLA_PORT_RESPONSE field; Returns 0 in
|
|
|
|
* case of success, < 0 otherwise with error having been reported
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileGetStatus(struct nlattr **tb, int32_t vf,
|
|
|
|
const unsigned char *instanceId,
|
|
|
|
bool nltarget_kernel,
|
|
|
|
bool is8021Qbg,
|
|
|
|
uint16_t *status)
|
|
|
|
{
|
|
|
|
struct nlattr *tb_port[IFLA_PORT_MAX + 1] = { NULL, };
|
|
|
|
|
|
|
|
if (vf == PORT_SELF_VF && nltarget_kernel) {
|
|
|
|
if (tb[IFLA_PORT_SELF]) {
|
|
|
|
if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb[IFLA_PORT_SELF],
|
|
|
|
ifla_port_policy)) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("error parsing IFLA_PORT_SELF part"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("IFLA_PORT_SELF is missing"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (tb[IFLA_VF_PORTS]) {
|
|
|
|
int rem;
|
|
|
|
bool found = false;
|
|
|
|
struct nlattr *tb_vf_ports = { NULL, };
|
|
|
|
|
|
|
|
nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
|
|
|
|
|
|
|
|
if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("error while iterating over "
|
|
|
|
"IFLA_VF_PORTS part"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb_vf_ports,
|
|
|
|
ifla_port_policy)) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("error parsing IFLA_VF_PORT part"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 22:08:43 +00:00
|
|
|
/* This ensures that the given VF is present in the
|
|
|
|
* IFLA_VF_PORTS list, and that its uuid matches the
|
|
|
|
* instanceId (in case we've associated it). If no
|
|
|
|
* instanceId is sent from the caller, that means we've
|
|
|
|
* disassociated it from this instanceId, and the uuid
|
|
|
|
* will either be unset (if still not associated with
|
|
|
|
* anything) or will be set to a new and different uuid
|
|
|
|
*/
|
|
|
|
if ((tb_port[IFLA_PORT_VF] &&
|
|
|
|
vf == *(uint32_t *)RTA_DATA(tb_port[IFLA_PORT_VF])) &&
|
|
|
|
(!instanceId ||
|
|
|
|
(tb_port[IFLA_PORT_INSTANCE_UUID] &&
|
|
|
|
!memcmp(instanceId,
|
|
|
|
(unsigned char *)
|
|
|
|
RTA_DATA(tb_port[IFLA_PORT_INSTANCE_UUID]),
|
|
|
|
VIR_UUID_BUFLEN)))) {
|
2011-11-02 17:11:02 +00:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
2015-12-18 21:40:29 +00:00
|
|
|
char instanceIdStr[VIR_UUID_STRING_BUFLEN] = "(none)";
|
|
|
|
|
|
|
|
if (instanceId)
|
|
|
|
virUUIDFormat(instanceId, instanceIdStr);
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Could not find vf/instanceId %u/%s "
|
|
|
|
" in netlink response"),
|
|
|
|
vf, instanceIdStr);
|
|
|
|
|
|
|
|
/* go through all the entries again. This seems tedious,
|
|
|
|
* but experience has shown the resulting log to be
|
|
|
|
* very useful.
|
|
|
|
*/
|
|
|
|
VIR_WARN("IFLA_VF_PORTS entries that were returned:");
|
|
|
|
nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN] = "(none)";
|
|
|
|
|
|
|
|
if (nla_parse_nested(tb_port, IFLA_PORT_MAX, tb_vf_ports,
|
|
|
|
ifla_port_policy)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("error parsing IFLA_VF_PORT "
|
|
|
|
"during error reporting"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2015-12-18 21:40:29 +00:00
|
|
|
}
|
|
|
|
if (tb_port[IFLA_PORT_INSTANCE_UUID]) {
|
|
|
|
virUUIDFormat((unsigned char *)
|
|
|
|
RTA_DATA(tb_port[IFLA_PORT_INSTANCE_UUID]),
|
|
|
|
uuidstr);
|
|
|
|
}
|
|
|
|
VIR_WARN(" vf: %d uuid: %s",
|
|
|
|
tb_port[IFLA_PORT_VF] ?
|
|
|
|
*(uint32_t *)RTA_DATA(tb_port[IFLA_PORT_VF]) : -1,
|
|
|
|
uuidstr);
|
2016-01-08 19:09:31 +00:00
|
|
|
}
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("IFLA_VF_PORTS is missing"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb_port[IFLA_PORT_RESPONSE]) {
|
|
|
|
*status = *(uint16_t *)RTA_DATA(tb_port[IFLA_PORT_RESPONSE]);
|
|
|
|
} else {
|
|
|
|
if (is8021Qbg) {
|
|
|
|
/* no in-progress here; may be missing */
|
|
|
|
*status = PORT_PROFILE_RESPONSE_INPROGRESS;
|
|
|
|
} else {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
_("no IFLA_PORT_RESPONSE found in netlink message"));
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-06 21:57:45 +00:00
|
|
|
|
|
|
|
return 0;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileOpSetLink(const char *ifname, int ifindex,
|
|
|
|
bool nltarget_kernel,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr,
|
2011-11-02 17:11:02 +00:00
|
|
|
int vlanid,
|
|
|
|
const char *profileId,
|
|
|
|
struct ifla_port_vsi *portVsi,
|
|
|
|
const unsigned char *instanceId,
|
|
|
|
const unsigned char *hostUUID,
|
|
|
|
int32_t vf,
|
|
|
|
uint8_t op)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
2013-04-03 13:09:19 +00:00
|
|
|
struct nlmsghdr *resp = NULL;
|
2011-11-02 17:11:02 +00:00
|
|
|
struct nlmsgerr *err;
|
|
|
|
struct ifinfomsg ifinfo = {
|
|
|
|
.ifi_family = AF_UNSPEC,
|
|
|
|
.ifi_index = ifindex,
|
|
|
|
};
|
|
|
|
unsigned int recvbuflen = 0;
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
int src_pid = 0;
|
|
|
|
uint32_t dst_pid = 0;
|
2011-11-02 17:11:02 +00:00
|
|
|
struct nl_msg *nl_msg;
|
|
|
|
struct nlattr *vfports = NULL, *vfport;
|
2016-02-11 20:24:17 +00:00
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
char hostUUIDStr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char instanceUUIDStr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
const char *opName;
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case PORT_REQUEST_PREASSOCIATE:
|
|
|
|
opName = "PREASSOCIATE";
|
|
|
|
break;
|
|
|
|
case PORT_REQUEST_PREASSOCIATE_RR:
|
|
|
|
opName = "PREASSOCIATE_RR";
|
|
|
|
break;
|
|
|
|
case PORT_REQUEST_ASSOCIATE:
|
|
|
|
opName = "ASSOCIATE";
|
|
|
|
break;
|
|
|
|
case PORT_REQUEST_DISASSOCIATE:
|
|
|
|
opName = "DISASSOCIATE";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
opName = "(unknown)";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
VIR_INFO("%s: ifname: %s ifindex: %d vf: %d vlanid: %d mac: %s "
|
|
|
|
"profileId: %s instanceId: %s hostUUID: %s",
|
|
|
|
opName, ifname ? ifname : "(unspecified)",
|
|
|
|
ifindex, vf, vlanid,
|
|
|
|
macaddr ? virMacAddrFormat(macaddr, macStr) : "(unspecified)",
|
|
|
|
profileId ? profileId : "(unspecified)",
|
|
|
|
(instanceId
|
|
|
|
? virUUIDFormat(instanceId, instanceUUIDStr)
|
|
|
|
: "(unspecified)"),
|
|
|
|
(hostUUID
|
|
|
|
? virUUIDFormat(hostUUID, hostUUIDStr)
|
|
|
|
: "(unspecified)"));
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
nl_msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_REQUEST);
|
|
|
|
if (!nl_msg) {
|
|
|
|
virReportOOMError();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (ifname &&
|
|
|
|
nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (macaddr || vlanid >= 0) {
|
|
|
|
struct nlattr *vfinfolist, *vfinfo;
|
|
|
|
|
|
|
|
if (!(vfinfolist = nla_nest_start(nl_msg, IFLA_VFINFO_LIST)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
if (macaddr) {
|
|
|
|
struct ifla_vf_mac ifla_vf_mac = {
|
|
|
|
.vf = vf,
|
|
|
|
.mac = { 0, },
|
|
|
|
};
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrGetRaw(macaddr, ifla_vf_mac.mac);
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_VF_MAC, sizeof(ifla_vf_mac),
|
|
|
|
&ifla_vf_mac) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vlanid >= 0) {
|
|
|
|
struct ifla_vf_vlan ifla_vf_vlan = {
|
|
|
|
.vf = vf,
|
|
|
|
.vlan = vlanid,
|
|
|
|
.qos = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof(ifla_vf_vlan),
|
|
|
|
&ifla_vf_vlan) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(nl_msg, vfinfo);
|
|
|
|
nla_nest_end(nl_msg, vfinfolist);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vf == PORT_SELF_VF && nltarget_kernel) {
|
|
|
|
if (!(vfport = nla_nest_start(nl_msg, IFLA_PORT_SELF)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
} else {
|
|
|
|
if (!(vfports = nla_nest_start(nl_msg, IFLA_VF_PORTS)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
/* begin nesting vfports */
|
|
|
|
if (!(vfport = nla_nest_start(nl_msg, IFLA_VF_PORT)))
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profileId) {
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_PROFILE, strlen(profileId) + 1,
|
|
|
|
profileId) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (portVsi) {
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_VSI_TYPE, sizeof(*portVsi),
|
|
|
|
portVsi) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (instanceId) {
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_INSTANCE_UUID, VIR_UUID_BUFLEN,
|
|
|
|
instanceId) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hostUUID) {
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_HOST_UUID, VIR_UUID_BUFLEN,
|
|
|
|
hostUUID) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vf != PORT_SELF_VF) {
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_VF, sizeof(vf), &vf) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nla_put(nl_msg, IFLA_PORT_REQUEST, sizeof(op), &op) < 0)
|
|
|
|
goto buffer_too_small;
|
|
|
|
|
|
|
|
/* end nesting of vport */
|
|
|
|
nla_nest_end(nl_msg, vfport);
|
|
|
|
|
|
|
|
if (vfports) {
|
|
|
|
/* end nesting of vfports */
|
|
|
|
nla_nest_end(nl_msg, vfports);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nltarget_kernel) {
|
2012-08-22 04:10:23 +00:00
|
|
|
if ((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0)
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
if ((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0)
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
2013-04-03 13:09:19 +00:00
|
|
|
if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
|
2012-08-22 04:10:23 +00:00
|
|
|
src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2013-04-03 13:09:19 +00:00
|
|
|
if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
|
2011-11-02 17:11:02 +00:00
|
|
|
goto malformed_resp;
|
|
|
|
|
|
|
|
switch (resp->nlmsg_type) {
|
|
|
|
case NLMSG_ERROR:
|
|
|
|
err = (struct nlmsgerr *)NLMSG_DATA(resp);
|
|
|
|
if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
|
|
|
|
goto malformed_resp;
|
|
|
|
|
|
|
|
if (err->error) {
|
|
|
|
virReportSystemError(-err->error,
|
2018-09-19 08:38:14 +00:00
|
|
|
_("error during virtual port configuration of ifindex %d"),
|
|
|
|
ifindex);
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NLMSG_DONE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto malformed_resp;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2011-11-02 17:11:02 +00:00
|
|
|
nlmsg_free(nl_msg);
|
2013-04-03 13:09:19 +00:00
|
|
|
VIR_FREE(resp);
|
2011-11-02 17:11:02 +00:00
|
|
|
return rc;
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
malformed_resp:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-02 17:11:02 +00:00
|
|
|
_("malformed netlink response message"));
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
buffer_too_small:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-02 17:11:02 +00:00
|
|
|
_("allocated netlink buffer is too small"));
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-03 13:41:40 +00:00
|
|
|
/**
|
|
|
|
* virNetDevVPortProfileGetNthParent
|
|
|
|
*
|
|
|
|
* @ifname : the name of the interface; ignored if ifindex is valid
|
|
|
|
* @ifindex : the index of the interface or -1 if ifname is given
|
|
|
|
* @nthParent : the nth parent interface to get
|
|
|
|
* @parent_ifindex : pointer to int
|
|
|
|
* @parent_ifname : pointer to buffer of size IFNAMSIZ
|
|
|
|
* @nth : the nth parent that is actually returned; if for example eth0.100
|
|
|
|
* was given and the 100th parent is to be returned, then eth0 will
|
|
|
|
* most likely be returned with nth set to 1 since the chain does
|
|
|
|
* not have more interfaces
|
|
|
|
*
|
|
|
|
* Get the nth parent interface of the given interface. 0 is the interface
|
|
|
|
* itself.
|
|
|
|
*
|
|
|
|
* Return 0 on success, < 0 otherwise
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileGetNthParent(const char *ifname, int ifindex, unsigned int nthParent,
|
|
|
|
int *parent_ifindex, char *parent_ifname,
|
|
|
|
unsigned int *nth)
|
|
|
|
{
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
int rc = -1;
|
|
|
|
void *nlData = NULL;
|
2011-11-03 13:41:40 +00:00
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
|
|
|
|
bool end = false;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i = 0;
|
2011-11-03 13:41:40 +00:00
|
|
|
|
|
|
|
*nth = 0;
|
|
|
|
|
|
|
|
if (ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (!end && i <= nthParent) {
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
VIR_FREE(nlData);
|
2016-06-13 11:59:12 +00:00
|
|
|
rc = virNetlinkDumpLink(ifname, ifindex, &nlData, tb, 0, 0);
|
2011-11-03 13:41:40 +00:00
|
|
|
if (rc < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (tb[IFLA_IFNAME]) {
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]),
|
|
|
|
IFNAMSIZ) < 0) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-03 13:41:40 +00:00
|
|
|
_("buffer for root interface name is too small"));
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
rc = -1;
|
|
|
|
goto cleanup;
|
2011-11-03 13:41:40 +00:00
|
|
|
}
|
|
|
|
*parent_ifindex = ifindex;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tb[IFLA_LINK]) {
|
|
|
|
ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]);
|
|
|
|
ifname = NULL;
|
2014-09-03 19:39:21 +00:00
|
|
|
} else {
|
2011-11-03 13:41:40 +00:00
|
|
|
end = true;
|
2014-09-03 19:39:21 +00:00
|
|
|
}
|
2011-11-03 13:41:40 +00:00
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*nth = i - 1;
|
|
|
|
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(nlData);
|
2011-11-03 13:41:40 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-02 17:11:02 +00:00
|
|
|
/* Returns 0 on success, -1 on general failure, and -2 on timeout */
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileOpCommon(const char *ifname, int ifindex,
|
|
|
|
bool nltarget_kernel,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr,
|
2011-11-02 17:11:02 +00:00
|
|
|
int vlanid,
|
|
|
|
const char *profileId,
|
|
|
|
struct ifla_port_vsi *portVsi,
|
|
|
|
const unsigned char *instanceId,
|
|
|
|
const unsigned char *hostUUID,
|
|
|
|
int32_t vf,
|
2012-02-22 13:17:14 +00:00
|
|
|
uint8_t op,
|
|
|
|
bool setlink_only)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
int rc;
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
int src_pid = 0;
|
|
|
|
uint32_t dst_pid = 0;
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
void *nlData = NULL;
|
2013-11-19 23:00:32 +00:00
|
|
|
struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
|
2011-11-02 17:11:02 +00:00
|
|
|
int repeats = STATUS_POLL_TIMEOUT_USEC / STATUS_POLL_INTERVL_USEC;
|
|
|
|
uint16_t status = 0;
|
|
|
|
bool is8021Qbg = (profileId == NULL);
|
|
|
|
|
|
|
|
rc = virNetDevVPortProfileOpSetLink(ifname, ifindex,
|
|
|
|
nltarget_kernel,
|
|
|
|
macaddr,
|
|
|
|
vlanid,
|
|
|
|
profileId,
|
|
|
|
portVsi,
|
|
|
|
instanceId,
|
|
|
|
hostUUID,
|
|
|
|
vf,
|
|
|
|
op);
|
|
|
|
if (rc < 0) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-02 17:11:02 +00:00
|
|
|
_("sending of PortProfileRequest failed."));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-01-24 20:30:04 +00:00
|
|
|
if (setlink_only) /* for re-associations on existing links */
|
2012-02-22 13:17:14 +00:00
|
|
|
return 0;
|
|
|
|
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
if (!nltarget_kernel &&
|
2012-08-22 04:10:23 +00:00
|
|
|
(((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0) ||
|
util: set src_pid for virNetlinkCommand when appropriate
Until now, the nl_pid of the source address of every message sent by
virNetlinkCommand has been set to the value of getpid(). Most of the
time this doesn't matter, and in the one case where it does
(communication with lldpad), it previously was the proper thing to do,
because the netlink event service (which listens on a netlink socket
for unsolicited messages from lldpad) coincidentally always happened
to bind with a local nl_pid == getpid().
With the fix for:
https://bugzilla.redhat.com/show_bug.cgi?id=816465
that particular nl_pid is now effectively a reserved value, so the
netlink event service will always bind to something else
(coincidentally "getpid() + (1 << 22)", but it really could be
anything). The result is that communication between lldpad and
libvirtd is broken (lldpad gets a "disconnected" error when it tries
to send a directed message).
The solution to this problem caused by a solution, is to query the
netlink event service's nlhandle for its "local_port", and send that
as the source nl_pid (but only when sending to lldpad, of course - in
other cases we maintain the old behavior of sending getpid()).
There are two cases where a message is being directed at lldpad - one
in virNetDevLinkDump, and one in virNetDevVPortProfileOpSetLink.
The case of virNetDevVPortProfileOpSetLink is simplest to explain -
only if !nltarget_kernel, i.e. the message isn't targetted for the
kernel, is the dst_pid set (by calling
virNetDevVPortProfileGetLldpadPid()), so only in that case do we call
virNetlinkEventServiceLocalPid() to set src_pid.
For virNetDevLinkDump, it's a bit more complicated. The call to
virNetDevVPortProfileGetLldpadPid() was effectively up one level (in
virNetDevVPortProfileOpCommon), although obscured by an unnecessary
passing of a function pointer. This patch removes the function
pointer, and calls virNetDevVPortProfileGetLldpadPid() directly in
virNetDevVPortProfileOpCommon - if it's doing this, it knows that it
should also call virNetlinkEventServiceLocalPid() to set src_pid too;
then it just passes src_pid and dst_pid down to
virNetDevLinkDump. Since (src_pid == 0 && dst_pid == 0) implies that
the kernel is the destination, there is no longer any need to send
nltarget_kernel as an arg to virNetDevLinkDump, so it's been removed.
The disparity between src_pid being int and dst_pid being uint32_t may
be a bit disconcerting to some, but I didn't want to complicate
virNetlinkEventServiceLocalPid() by having status returned separately
from the value.
2012-05-04 17:48:20 +00:00
|
|
|
((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0))) {
|
|
|
|
rc = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-11-02 17:11:02 +00:00
|
|
|
while (--repeats >= 0) {
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
VIR_FREE(nlData);
|
2016-06-13 11:59:12 +00:00
|
|
|
rc = virNetlinkDumpLink(NULL, ifindex, &nlData, tb, src_pid, dst_pid);
|
2011-11-02 17:11:02 +00:00
|
|
|
if (rc < 0)
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
rc = virNetDevVPortProfileGetStatus(tb, vf, instanceId, nltarget_kernel,
|
|
|
|
is8021Qbg, &status);
|
|
|
|
if (rc < 0)
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
if (status == PORT_PROFILE_RESPONSE_SUCCESS ||
|
|
|
|
status == PORT_VDP_RESPONSE_SUCCESS) {
|
|
|
|
break;
|
|
|
|
} else if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
|
|
|
|
/* keep trying... */
|
|
|
|
} else {
|
|
|
|
virReportSystemError(EINVAL,
|
2018-09-19 08:38:14 +00:00
|
|
|
_("error %d during port-profile setlink on "
|
|
|
|
"interface %s (%d)"),
|
|
|
|
status, ifname, ifindex);
|
2011-11-02 17:11:02 +00:00
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(STATUS_POLL_INTERVL_USEC);
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2011-11-02 17:11:02 +00:00
|
|
|
_("port-profile setlink timed out"));
|
|
|
|
rc = -2;
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
util: eliminate "use after free" in callers of virNetDevLinkDump
virNetDevLinkDump() gets a message from netlink into "resp", then
calls nlmsg_parse() to fill the table "tb" with pointers into resp. It
then returns tb to its caller, but not before freeing the buffer at
resp. That means that all the callers of virNetDevLinkDump() are
examining memory that has already been freed. This can be verified by
filling the buffer at resp with garbage prior to freeing it (or, I
suppose, just running libvirtd under valgrind) then performing some
operation that calls virNetDevLinkDump().
The code has been like this ever since virNetDevLinkDump() was written
- the original author didn't notice it, and neither did later
additional users of the function. It has only been pure luck (or maybe
a lack of heavy load, and/or maybe an allocation algorithm in malloc()
that delays re-use of just-freed memory) that has kept this from
causing errors, for example when configuring a PCI passthrough or
macvtap passthrough network interface.
The solution taken in this patch is the simplest - just return resp to
the caller along with tb, then have the caller free it after they are
finished using the data (pointers) in tb. I alternately could have
made a cleaner interface by creating a new struct that put tb and resp
together along with a vir*Free() function for it, but this function is
only used in a couple places, and I'm not sure there will be
additional new uses of virNetDevLinkDump(), so the value of adding a
new type, extra APIs, etc. is dubious.
2014-10-15 22:49:01 +00:00
|
|
|
VIR_FREE(nlData);
|
2011-11-02 17:11:02 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileGetPhysdevAndVlan(const char *ifname, int *root_ifindex, char *root_ifname,
|
|
|
|
int *vlanid)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
unsigned int nth;
|
|
|
|
int ifindex = -1;
|
|
|
|
|
|
|
|
*vlanid = -1;
|
|
|
|
while (1) {
|
2011-11-03 13:41:40 +00:00
|
|
|
if ((ret = virNetDevVPortProfileGetNthParent(ifname, ifindex, 1,
|
|
|
|
root_ifindex, root_ifname, &nth)) < 0)
|
2011-11-02 17:11:02 +00:00
|
|
|
return ret;
|
|
|
|
if (nth == 0)
|
|
|
|
break;
|
|
|
|
if (*vlanid == -1) {
|
2011-11-03 09:21:35 +00:00
|
|
|
if (virNetDevGetVLanID(root_ifname, vlanid) < 0) {
|
|
|
|
virResetLastError();
|
2011-11-02 17:11:02 +00:00
|
|
|
*vlanid = -1;
|
2011-11-03 09:21:35 +00:00
|
|
|
}
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ifindex = *root_ifindex;
|
|
|
|
ifname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns 0 on success, -1 on general failure, and -2 on timeout */
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileOp8021Qbg(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr,
|
2012-03-06 01:12:39 +00:00
|
|
|
int vf,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virNetDevVPortProfile *virtPort,
|
2012-02-22 13:17:14 +00:00
|
|
|
enum virNetDevVPortProfileLinkOp virtPortOp,
|
|
|
|
bool setlink_only)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
int op = PORT_REQUEST_ASSOCIATE;
|
|
|
|
struct ifla_port_vsi portVsi = {
|
2012-07-25 01:14:41 +00:00
|
|
|
.vsi_mgr_id = virtPort->managerID,
|
|
|
|
.vsi_type_version = virtPort->typeIDVersion,
|
2011-11-02 17:11:02 +00:00
|
|
|
};
|
|
|
|
bool nltarget_kernel = false;
|
|
|
|
int vlanid;
|
|
|
|
int physdev_ifindex = 0;
|
|
|
|
char physdev_ifname[IFNAMSIZ] = { 0, };
|
2012-03-06 01:12:39 +00:00
|
|
|
|
|
|
|
if (!ifname)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vf = PORT_SELF_VF;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
util: standardize return from functions calling virNetlinkCommand
There are several functions that call virNetlinkCommand, and they all
follow a common pattern, with three exit labels: err_exit (or
cleanup), malformed_resp, and buffer_too_small. All three of these
labels do their own cleanup and have their own return. However, the
malformed_resp label usually frees the same items as the
cleanup/err_exit label, and the buffer_too_small label just doesn't
free recvbuf (because it's known to always be NULL at the time we goto
buffer_too_small.
In order to simplify and standardize the code, I've made the following
changes to all of these functions:
1) err_exit is replaced with the more libvirt-ish "cleanup", which
makes sense because in all cases this code is also executed in the
case of success, so labelling it err_exit may be confusing.
2) rc is initialized to -1, and set to 0 just before the cleanup
label. Any code that currently sets rc = -1 is made to instead goto
cleanup.
3) malformed_resp and buffer_too_small just log their error and goto
cleanup. This gives us a single return path, and a single place to
free up resources.
4) In one instance, rather then logging an error immediately, a char*
msg was pointed to an error string, then goto cleanup (and cleanup
would log an error if msg != NULL). It takes no more lines of code
to just log the message as we encounter it.
This patch should have 0 functional effects.
2012-03-07 17:44:56 +00:00
|
|
|
if (virNetDevVPortProfileGetPhysdevAndVlan(ifname, &physdev_ifindex,
|
|
|
|
physdev_ifname, &vlanid) < 0) {
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vlanid < 0)
|
|
|
|
vlanid = 0;
|
|
|
|
|
2012-07-25 01:14:41 +00:00
|
|
|
portVsi.vsi_type_id[2] = virtPort->typeID >> 16;
|
|
|
|
portVsi.vsi_type_id[1] = virtPort->typeID >> 8;
|
|
|
|
portVsi.vsi_type_id[0] = virtPort->typeID;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
switch (virtPortOp) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE:
|
|
|
|
op = PORT_REQUEST_PREASSOCIATE;
|
|
|
|
break;
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR:
|
|
|
|
op = PORT_REQUEST_PREASSOCIATE_RR;
|
|
|
|
break;
|
2011-11-02 17:11:02 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE:
|
|
|
|
op = PORT_REQUEST_ASSOCIATE;
|
|
|
|
break;
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE:
|
|
|
|
op = PORT_REQUEST_DISASSOCIATE;
|
|
|
|
break;
|
|
|
|
default:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-11-02 17:11:02 +00:00
|
|
|
_("operation type %d not supported"), virtPortOp);
|
2020-01-06 21:57:45 +00:00
|
|
|
return -1;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
2020-01-06 21:57:45 +00:00
|
|
|
return virNetDevVPortProfileOpCommon(physdev_ifname, physdev_ifindex,
|
|
|
|
nltarget_kernel,
|
|
|
|
macaddr,
|
|
|
|
vlanid,
|
|
|
|
NULL,
|
|
|
|
&portVsi,
|
|
|
|
virtPort->instanceID,
|
|
|
|
NULL,
|
|
|
|
vf,
|
|
|
|
op,
|
|
|
|
setlink_only);
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns 0 on success, -1 on general failure, and -2 on timeout */
|
|
|
|
static int
|
|
|
|
virNetDevVPortProfileOp8021Qbh(const char *ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virMacAddr *macaddr,
|
2012-03-06 01:12:39 +00:00
|
|
|
int32_t vf,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virNetDevVPortProfile *virtPort,
|
2011-11-02 17:11:02 +00:00
|
|
|
const unsigned char *vm_uuid,
|
|
|
|
enum virNetDevVPortProfileLinkOp virtPortOp)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
char *physfndev = NULL;
|
|
|
|
unsigned char hostuuid[VIR_UUID_BUFLEN];
|
|
|
|
bool nltarget_kernel = true;
|
|
|
|
int ifindex;
|
|
|
|
int vlanid = -1;
|
2012-03-06 01:12:39 +00:00
|
|
|
bool is_vf = false;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2012-03-06 01:12:39 +00:00
|
|
|
if (vf == -1) {
|
|
|
|
int isvf_ret = virNetDevIsVirtualFunction(ifname);
|
|
|
|
|
|
|
|
if (isvf_ret == -1)
|
|
|
|
goto cleanup;
|
|
|
|
is_vf = !!isvf_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_vf) {
|
|
|
|
if (virNetDevGetVirtualFunctionInfo(ifname, &physfndev, &vf) < 0) {
|
|
|
|
rc = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2019-10-20 11:49:46 +00:00
|
|
|
physfndev = g_strdup(ifname);
|
2012-03-06 01:12:39 +00:00
|
|
|
}
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2011-11-03 09:21:35 +00:00
|
|
|
rc = virNetDevGetIndex(physfndev, &ifindex);
|
2011-11-02 17:11:02 +00:00
|
|
|
if (rc < 0)
|
2012-03-06 01:12:39 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
switch (virtPortOp) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR:
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE:
|
|
|
|
errno = virGetHostUUID(hostuuid);
|
|
|
|
if (errno) {
|
|
|
|
rc = -1;
|
2012-03-06 01:12:39 +00:00
|
|
|
goto cleanup;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = virNetDevVPortProfileOpCommon(NULL, ifindex,
|
|
|
|
nltarget_kernel,
|
|
|
|
macaddr,
|
|
|
|
vlanid,
|
2012-07-25 01:14:41 +00:00
|
|
|
virtPort->profileID,
|
2011-11-02 17:11:02 +00:00
|
|
|
NULL,
|
|
|
|
vm_uuid,
|
|
|
|
hostuuid,
|
|
|
|
vf,
|
|
|
|
(virtPortOp ==
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR) ?
|
|
|
|
PORT_REQUEST_PREASSOCIATE_RR
|
2012-02-22 13:17:14 +00:00
|
|
|
: PORT_REQUEST_ASSOCIATE,
|
|
|
|
false);
|
2011-11-02 17:11:02 +00:00
|
|
|
if (rc == -2)
|
|
|
|
/* Association timed out, disassociate */
|
|
|
|
virNetDevVPortProfileOpCommon(NULL, ifindex,
|
|
|
|
nltarget_kernel,
|
|
|
|
NULL,
|
|
|
|
vlanid,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
vf,
|
2012-02-22 13:17:14 +00:00
|
|
|
PORT_REQUEST_DISASSOCIATE,
|
|
|
|
false);
|
2011-11-02 17:11:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE:
|
|
|
|
rc = virNetDevVPortProfileOpCommon(NULL, ifindex,
|
|
|
|
nltarget_kernel,
|
|
|
|
NULL,
|
|
|
|
vlanid,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
vf,
|
2012-02-22 13:17:14 +00:00
|
|
|
PORT_REQUEST_DISASSOCIATE,
|
|
|
|
false);
|
2011-11-02 17:11:02 +00:00
|
|
|
break;
|
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE:
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-11-02 17:11:02 +00:00
|
|
|
_("operation type %d not supported"), virtPortOp);
|
|
|
|
rc = -1;
|
2018-02-14 09:43:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virNetDevVPortProfileType, virtPortOp);
|
|
|
|
rc = -1;
|
|
|
|
break;
|
2011-11-02 17:11:02 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2011-11-02 17:11:02 +00:00
|
|
|
VIR_FREE(physfndev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevVPortProfileAssociate:
|
|
|
|
*
|
|
|
|
* @macvtap_ifname: The name of the macvtap device
|
|
|
|
* @virtPort: pointer to the object holding port profile parameters
|
|
|
|
* @vmuuid : the UUID of the virtual machine
|
|
|
|
* @vmOp : The VM operation (i.e., create, no-op)
|
2012-02-22 13:17:14 +00:00
|
|
|
* @setlink_only : Only set the link - dont wait for the link to come up
|
2011-11-02 17:11:02 +00:00
|
|
|
*
|
2013-08-15 22:45:20 +00:00
|
|
|
* Associate a port on a switch with a profile. This function
|
2011-11-02 17:11:02 +00:00
|
|
|
* may notify a kernel driver or an external daemon to run
|
|
|
|
* the setup protocol. If profile parameters were not supplied
|
|
|
|
* by the user, then this function returns without doing
|
|
|
|
* anything.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, < 0 otherwise with error
|
|
|
|
* having been reported.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevVPortProfileAssociate(const char *macvtap_ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virNetDevVPortProfile *virtPort,
|
|
|
|
const virMacAddr *macvtap_macaddr,
|
2011-11-02 17:11:02 +00:00
|
|
|
const char *linkdev,
|
2012-03-06 01:12:39 +00:00
|
|
|
int vf,
|
2011-11-02 17:11:02 +00:00
|
|
|
const unsigned char *vmuuid,
|
2014-04-27 00:15:22 +00:00
|
|
|
virNetDevVPortProfileOp vmOp,
|
2012-02-22 13:17:14 +00:00
|
|
|
bool setlink_only)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2016-02-11 20:24:17 +00:00
|
|
|
char uuidStr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
2011-11-02 17:11:02 +00:00
|
|
|
|
2016-02-11 20:24:17 +00:00
|
|
|
VIR_DEBUG("profile:'%p' vmOp: %s device: %s@%s mac: %s uuid: %s",
|
|
|
|
virtPort, virNetDevVPortProfileOpTypeToString(vmOp),
|
2019-02-12 16:25:06 +00:00
|
|
|
NULLSTR_EMPTY(macvtap_ifname), linkdev,
|
2016-02-11 20:24:17 +00:00
|
|
|
(macvtap_macaddr
|
|
|
|
? virMacAddrFormat(macvtap_macaddr, macStr)
|
|
|
|
: "(unspecified)"),
|
|
|
|
vmuuid ? virUUIDFormat(vmuuid, uuidStr) : "(unspecified)");
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
if (!virtPort || vmOp == VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (virtPort->virtPortType) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_NONE:
|
2012-02-10 21:09:00 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
2011-11-02 17:11:02 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LAST:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
|
|
|
rc = virNetDevVPortProfileOp8021Qbg(macvtap_ifname, macvtap_macaddr,
|
2012-03-06 01:12:39 +00:00
|
|
|
vf, virtPort,
|
2011-11-02 17:11:02 +00:00
|
|
|
(vmOp == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START)
|
|
|
|
? VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE
|
2012-02-22 13:17:14 +00:00
|
|
|
: VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE,
|
|
|
|
setlink_only);
|
2011-11-02 17:11:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
2012-03-06 01:12:39 +00:00
|
|
|
rc = virNetDevVPortProfileOp8021Qbh(linkdev, macvtap_macaddr, vf,
|
2011-11-02 17:11:02 +00:00
|
|
|
virtPort, vmuuid,
|
|
|
|
(vmOp == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START)
|
|
|
|
? VIR_NETDEV_VPORT_PROFILE_LINK_OP_PREASSOCIATE_RR
|
|
|
|
: VIR_NETDEV_VPORT_PROFILE_LINK_OP_ASSOCIATE);
|
|
|
|
if (vmOp != VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START && !rc) {
|
|
|
|
/* XXX bogus error handling */
|
|
|
|
ignore_value(virNetDevSetOnline(linkdev, true));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetDevVPortProfileDisassociate:
|
|
|
|
*
|
|
|
|
* @macvtap_ifname: The name of the macvtap device
|
|
|
|
* @macvtap_macaddr : The MAC address of the macvtap
|
|
|
|
* @linkdev: The link device in case of macvtap
|
|
|
|
* @virtPort: point to object holding port profile parameters
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, != 0 otherwise with error
|
|
|
|
* having been reported.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetDevVPortProfileDisassociate(const char *macvtap_ifname,
|
2013-10-05 19:41:44 +00:00
|
|
|
const virNetDevVPortProfile *virtPort,
|
|
|
|
const virMacAddr *macvtap_macaddr,
|
2011-11-02 17:11:02 +00:00
|
|
|
const char *linkdev,
|
2012-03-06 01:12:39 +00:00
|
|
|
int vf,
|
2014-04-27 00:15:22 +00:00
|
|
|
virNetDevVPortProfileOp vmOp)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2016-02-11 20:24:17 +00:00
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
|
|
|
VIR_DEBUG("profile:'%p' vmOp: %s device: %s@%s mac: %s",
|
|
|
|
virtPort, virNetDevVPortProfileOpTypeToString(vmOp),
|
2019-02-12 16:25:06 +00:00
|
|
|
NULLSTR_EMPTY(macvtap_ifname), linkdev,
|
2016-02-11 20:24:17 +00:00
|
|
|
(macvtap_macaddr
|
|
|
|
? virMacAddrFormat(macvtap_macaddr, macStr)
|
|
|
|
: "(unspecified)"));
|
2011-11-02 17:11:02 +00:00
|
|
|
|
|
|
|
if (!virtPort)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (virtPort->virtPortType) {
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_NONE:
|
2012-02-10 21:09:00 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
|
2011-11-02 17:11:02 +00:00
|
|
|
case VIR_NETDEV_VPORT_PROFILE_LAST:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBG:
|
2012-03-06 01:12:39 +00:00
|
|
|
rc = virNetDevVPortProfileOp8021Qbg(macvtap_ifname, macvtap_macaddr, vf,
|
2011-11-02 17:11:02 +00:00
|
|
|
virtPort,
|
2012-02-22 13:17:14 +00:00
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE, false);
|
2011-11-02 17:11:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETDEV_VPORT_PROFILE_8021QBH:
|
|
|
|
/* avoid disassociating twice */
|
|
|
|
if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH)
|
|
|
|
break;
|
2012-08-30 19:27:27 +00:00
|
|
|
if (vf < 0)
|
|
|
|
ignore_value(virNetDevSetOnline(linkdev, false));
|
2012-03-06 01:12:39 +00:00
|
|
|
rc = virNetDevVPortProfileOp8021Qbh(linkdev, macvtap_macaddr, vf,
|
2011-11-02 17:11:02 +00:00
|
|
|
virtPort, NULL,
|
|
|
|
VIR_NETDEV_VPORT_PROFILE_LINK_OP_DISASSOCIATE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-09-28 21:39:46 +00:00
|
|
|
#else /* !WITH_LIBNL */
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevVPortProfileAssociate(const char *macvtap_ifname G_GNUC_UNUSED,
|
|
|
|
const virNetDevVPortProfile *virtPort G_GNUC_UNUSED,
|
|
|
|
const virMacAddr *macvtap_macaddr G_GNUC_UNUSED,
|
|
|
|
const char *linkdev G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
const unsigned char *vmuuid G_GNUC_UNUSED,
|
|
|
|
virNetDevVPortProfileOp vmOp G_GNUC_UNUSED,
|
|
|
|
bool setlink_only G_GNUC_UNUSED)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Virtual port profile association not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-10-14 12:45:33 +00:00
|
|
|
int virNetDevVPortProfileDisassociate(const char *macvtap_ifname G_GNUC_UNUSED,
|
|
|
|
const virNetDevVPortProfile *virtPort G_GNUC_UNUSED,
|
|
|
|
const virMacAddr *macvtap_macaddr G_GNUC_UNUSED,
|
|
|
|
const char *linkdev G_GNUC_UNUSED,
|
|
|
|
int vf G_GNUC_UNUSED,
|
|
|
|
virNetDevVPortProfileOp vmOp G_GNUC_UNUSED)
|
2011-11-02 17:11:02 +00:00
|
|
|
{
|
|
|
|
virReportSystemError(ENOSYS, "%s",
|
|
|
|
_("Virtual port profile association not supported on this platform"));
|
|
|
|
return -1;
|
|
|
|
}
|
2020-09-28 21:39:46 +00:00
|
|
|
#endif /* !WITH_LIBNL */
|