mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-21 20:15:17 +00:00
virInterface: Expose link state & speed
Currently it is not possible to determine the speed of an interface and whether a link is actually detected from the API. Orchestrating platforms want to be able to determine when the link has failed and where multiple speeds may be available which one the interface is actually connected at. This commit introduces an extension to our interface XML (without implementation to interface driver backends): <interface type='ethernet' name='eth0'> <start mode='none'/> <mac address='aa:bb:cc:dd:ee:ff'/> <link speed='1000' state='up'/> <mtu size='1492'/> ... </interface> Where @speed is negotiated link speed in Mbits per second, and state is the current NIC state (can be one of the following: "unknown", "notpresent", "down", "lowerlayerdown","testing", "dormant", "up"). Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
10c10f4380
commit
3db89662c2
@ -397,4 +397,29 @@
|
|||||||
</optional>
|
</optional>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="link-speed-state">
|
||||||
|
<optional>
|
||||||
|
<element name="link">
|
||||||
|
<optional>
|
||||||
|
<attribute name="speed">
|
||||||
|
<ref name="unsignedInt"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="state">
|
||||||
|
<choice>
|
||||||
|
<value>unknown</value>
|
||||||
|
<value>notpresent</value>
|
||||||
|
<value>down</value>
|
||||||
|
<value>lowerlayerdown</value>
|
||||||
|
<value>testing</value>
|
||||||
|
<value>dormant</value>
|
||||||
|
<value>up</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
</define>
|
||||||
|
|
||||||
</grammar>
|
</grammar>
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<attribute name="address"><ref name="macAddr"/></attribute>
|
<attribute name="address"><ref name="macAddr"/></attribute>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<ref name="link-speed-state"/>
|
||||||
<!-- FIXME: Allow (some) ethtool options -->
|
<!-- FIXME: Allow (some) ethtool options -->
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
@ -38,6 +38,13 @@ VIR_ENUM_IMPL(virDeviceAddressPCIMulti,
|
|||||||
"on",
|
"on",
|
||||||
"off")
|
"off")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virInterfaceState,
|
||||||
|
VIR_INTERFACE_STATE_LAST,
|
||||||
|
"" /* value of zero means no state */,
|
||||||
|
"unknown", "notpresent",
|
||||||
|
"down", "lowerlayerdown",
|
||||||
|
"testing", "dormant", "up")
|
||||||
|
|
||||||
int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr)
|
int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr)
|
||||||
{
|
{
|
||||||
/* PCI bus has 32 slots and 8 functions per slot */
|
/* PCI bus has 32 slots and 8 functions per slot */
|
||||||
@ -142,3 +149,58 @@ virDevicePCIAddressEqual(virDevicePCIAddress *addr1,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
virInterfaceLinkParseXML(xmlNodePtr node,
|
||||||
|
virInterfaceLinkPtr lnk)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *stateStr, *speedStr;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
stateStr = virXMLPropString(node, "state");
|
||||||
|
speedStr = virXMLPropString(node, "speed");
|
||||||
|
|
||||||
|
if (stateStr) {
|
||||||
|
if ((state = virInterfaceStateTypeFromString(stateStr)) < 0) {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR,
|
||||||
|
_("unknown link state: %s"),
|
||||||
|
stateStr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
lnk->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedStr &&
|
||||||
|
virStrToLong_ui(speedStr, NULL, 10, &lnk->speed) < 0) {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR,
|
||||||
|
_("Unable to parse link speed: %s"),
|
||||||
|
speedStr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(stateStr);
|
||||||
|
VIR_FREE(speedStr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
virInterfaceLinkFormat(virBufferPtr buf,
|
||||||
|
const virInterfaceLink *lnk)
|
||||||
|
{
|
||||||
|
if (!lnk->speed && !lnk->state) {
|
||||||
|
/* If there's nothing to format, return early. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virBufferAddLit(buf, "<link");
|
||||||
|
if (lnk->speed)
|
||||||
|
virBufferAsprintf(buf, " speed='%u'", lnk->speed);
|
||||||
|
if (lnk->state)
|
||||||
|
virBufferAsprintf(buf, " state='%s'",
|
||||||
|
virInterfaceStateTypeToString(lnk->state));
|
||||||
|
virBufferAddLit(buf, "/>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -40,6 +40,21 @@ typedef enum {
|
|||||||
VIR_DEVICE_ADDRESS_PCI_MULTI_LAST
|
VIR_DEVICE_ADDRESS_PCI_MULTI_LAST
|
||||||
} virDeviceAddressPCIMulti;
|
} virDeviceAddressPCIMulti;
|
||||||
|
|
||||||
|
VIR_ENUM_DECL(virDeviceAddressPCIMulti)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VIR_INTERFACE_STATE_UNKNOWN = 1,
|
||||||
|
VIR_INTERFACE_STATE_NOT_PRESENT,
|
||||||
|
VIR_INTERFACE_STATE_DOWN,
|
||||||
|
VIR_INTERFACE_STATE_LOWER_LAYER_DOWN,
|
||||||
|
VIR_INTERFACE_STATE_TESTING,
|
||||||
|
VIR_INTERFACE_STATE_DORMANT,
|
||||||
|
VIR_INTERFACE_STATE_UP,
|
||||||
|
VIR_INTERFACE_STATE_LAST
|
||||||
|
} virInterfaceState;
|
||||||
|
|
||||||
|
VIR_ENUM_DECL(virInterfaceState)
|
||||||
|
|
||||||
typedef struct _virDevicePCIAddress virDevicePCIAddress;
|
typedef struct _virDevicePCIAddress virDevicePCIAddress;
|
||||||
typedef virDevicePCIAddress *virDevicePCIAddressPtr;
|
typedef virDevicePCIAddress *virDevicePCIAddressPtr;
|
||||||
struct _virDevicePCIAddress {
|
struct _virDevicePCIAddress {
|
||||||
@ -50,6 +65,13 @@ struct _virDevicePCIAddress {
|
|||||||
int multi; /* enum virDomainDeviceAddressPCIMulti */
|
int multi; /* enum virDomainDeviceAddressPCIMulti */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _virInterfaceLink virInterfaceLink;
|
||||||
|
typedef virInterfaceLink *virInterfaceLinkPtr;
|
||||||
|
struct _virInterfaceLink {
|
||||||
|
virInterfaceState state; /* link state */
|
||||||
|
unsigned int speed; /* link speed in Mbits per second */
|
||||||
|
};
|
||||||
|
|
||||||
int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr);
|
int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr);
|
||||||
|
|
||||||
int virDevicePCIAddressParseXML(xmlNodePtr node,
|
int virDevicePCIAddressParseXML(xmlNodePtr node,
|
||||||
@ -62,7 +84,10 @@ int virDevicePCIAddressFormat(virBufferPtr buf,
|
|||||||
bool virDevicePCIAddressEqual(virDevicePCIAddress *addr1,
|
bool virDevicePCIAddressEqual(virDevicePCIAddress *addr1,
|
||||||
virDevicePCIAddress *addr2);
|
virDevicePCIAddress *addr2);
|
||||||
|
|
||||||
|
int virInterfaceLinkParseXML(xmlNodePtr node,
|
||||||
|
virInterfaceLinkPtr lnk);
|
||||||
|
|
||||||
VIR_ENUM_DECL(virDeviceAddressPCIMulti)
|
int virInterfaceLinkFormat(virBufferPtr buf,
|
||||||
|
const virInterfaceLink *lnk);
|
||||||
|
|
||||||
#endif /* __DEVICE_CONF_H__ */
|
#endif /* __DEVICE_CONF_H__ */
|
||||||
|
@ -705,12 +705,19 @@ virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
|
|||||||
}
|
}
|
||||||
def->type = type;
|
def->type = type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VIR_INTERFACE_TYPE_ETHERNET:
|
case VIR_INTERFACE_TYPE_ETHERNET: {
|
||||||
|
xmlNodePtr lnk;
|
||||||
|
|
||||||
if (virInterfaceDefParseName(def, ctxt) < 0)
|
if (virInterfaceDefParseName(def, ctxt) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
tmp = virXPathString("string(./mac/@address)", ctxt);
|
tmp = virXPathString("string(./mac/@address)", ctxt);
|
||||||
if (tmp != NULL)
|
if (tmp != NULL)
|
||||||
def->mac = tmp;
|
def->mac = tmp;
|
||||||
|
|
||||||
|
lnk = virXPathNode("./link", ctxt);
|
||||||
|
if (lnk && virInterfaceLinkParseXML(lnk, &def->lnk) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
|
if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
|
||||||
/* only recognize these in toplevel bond interfaces */
|
/* only recognize these in toplevel bond interfaces */
|
||||||
if (virInterfaceDefParseStartMode(def, ctxt) < 0)
|
if (virInterfaceDefParseStartMode(def, ctxt) < 0)
|
||||||
@ -721,6 +728,7 @@ virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case VIR_INTERFACE_TYPE_BRIDGE: {
|
case VIR_INTERFACE_TYPE_BRIDGE: {
|
||||||
xmlNodePtr bridge;
|
xmlNodePtr bridge;
|
||||||
|
|
||||||
@ -1088,6 +1096,7 @@ virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def)
|
|||||||
virInterfaceStartmodeDefFormat(buf, def->startmode);
|
virInterfaceStartmodeDefFormat(buf, def->startmode);
|
||||||
if (def->mac != NULL)
|
if (def->mac != NULL)
|
||||||
virBufferAsprintf(buf, "<mac address='%s'/>\n", def->mac);
|
virBufferAsprintf(buf, "<mac address='%s'/>\n", def->mac);
|
||||||
|
virInterfaceLinkFormat(buf, &def->lnk);
|
||||||
if (def->mtu != 0)
|
if (def->mtu != 0)
|
||||||
virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
|
virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
|
||||||
virInterfaceProtocolDefFormat(buf, def);
|
virInterfaceProtocolDefFormat(buf, def);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
# include "internal.h"
|
# include "internal.h"
|
||||||
# include "virutil.h"
|
# include "virutil.h"
|
||||||
# include "virthread.h"
|
# include "virthread.h"
|
||||||
|
# include "device_conf.h"
|
||||||
|
|
||||||
/* There is currently 3 types of interfaces */
|
/* There is currently 3 types of interfaces */
|
||||||
|
|
||||||
@ -146,6 +147,7 @@ struct _virInterfaceDef {
|
|||||||
char *name; /* interface name */
|
char *name; /* interface name */
|
||||||
unsigned int mtu; /* maximum transmit size in byte */
|
unsigned int mtu; /* maximum transmit size in byte */
|
||||||
char *mac; /* MAC address */
|
char *mac; /* MAC address */
|
||||||
|
virInterfaceLink lnk; /* interface link info */
|
||||||
|
|
||||||
virInterfaceStartMode startmode; /* how it is started */
|
virInterfaceStartMode startmode; /* how it is started */
|
||||||
|
|
||||||
|
@ -83,6 +83,10 @@ virDevicePCIAddressEqual;
|
|||||||
virDevicePCIAddressFormat;
|
virDevicePCIAddressFormat;
|
||||||
virDevicePCIAddressIsValid;
|
virDevicePCIAddressIsValid;
|
||||||
virDevicePCIAddressParseXML;
|
virDevicePCIAddressParseXML;
|
||||||
|
virInterfaceLinkFormat;
|
||||||
|
virInterfaceLinkParseXML;
|
||||||
|
virInterfaceStateTypeFromString;
|
||||||
|
virInterfaceStateTypeToString;
|
||||||
|
|
||||||
|
|
||||||
# conf/domain_addr.h
|
# conf/domain_addr.h
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<bridge stp='off'>
|
<bridge stp='off'>
|
||||||
<interface type='ethernet' name='eth0'>
|
<interface type='ethernet' name='eth0'>
|
||||||
<mac address='ab:bb:cc:dd:ee:ff'/>
|
<mac address='ab:bb:cc:dd:ee:ff'/>
|
||||||
|
<link speed='1000' state='up'/>
|
||||||
</interface>
|
</interface>
|
||||||
<interface type='ethernet' name='eth1'>
|
<interface type='ethernet' name='eth1'>
|
||||||
</interface>
|
</interface>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<bridge stp='off' delay='0.01'>
|
<bridge stp='off' delay='0.01'>
|
||||||
<interface type='ethernet' name='eth0'>
|
<interface type='ethernet' name='eth0'>
|
||||||
<mac address='ab:bb:cc:dd:ee:ff'/>
|
<mac address='ab:bb:cc:dd:ee:ff'/>
|
||||||
|
<link speed='10'/>
|
||||||
</interface>
|
</interface>
|
||||||
<interface type='ethernet' name='eth1'>
|
<interface type='ethernet' name='eth1'>
|
||||||
</interface>
|
</interface>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<interface type='ethernet' name='eth0'>
|
<interface type='ethernet' name='eth0'>
|
||||||
<start mode='none'/>
|
<start mode='none'/>
|
||||||
<mac address='aa:bb:cc:dd:ee:ff'/>
|
<mac address='aa:bb:cc:dd:ee:ff'/>
|
||||||
|
<link state='down'/>
|
||||||
<mtu size='1492'/>
|
<mtu size='1492'/>
|
||||||
<protocol family='ipv4'>
|
<protocol family='ipv4'>
|
||||||
<dhcp peerdns='no'/>
|
<dhcp peerdns='no'/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user