From 3db89662c263d4707b02999aa12eb3b48d14fad3 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 7 May 2014 14:21:35 +0200 Subject: [PATCH] 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): ... 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 --- docs/schemas/basictypes.rng | 25 ++++++++ docs/schemas/interface.rng | 1 + src/conf/device_conf.c | 62 +++++++++++++++++++ src/conf/device_conf.h | 27 +++++++- src/conf/interface_conf.c | 11 +++- src/conf/interface_conf.h | 2 + src/libvirt_private.syms | 4 ++ .../interfaceschemadata/bridge-no-address.xml | 1 + tests/interfaceschemadata/bridge.xml | 1 + tests/interfaceschemadata/ethernet-dhcp.xml | 1 + 10 files changed, 133 insertions(+), 2 deletions(-) diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng index 34ef6137d9..5fe3a97dae 100644 --- a/docs/schemas/basictypes.rng +++ b/docs/schemas/basictypes.rng @@ -397,4 +397,29 @@ + + + + + + + + + + + + unknown + notpresent + down + lowerlayerdown + testing + dormant + up + + + + + + + diff --git a/docs/schemas/interface.rng b/docs/schemas/interface.rng index 3984b630a2..8e2218d1d7 100644 --- a/docs/schemas/interface.rng +++ b/docs/schemas/interface.rng @@ -41,6 +41,7 @@ + diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 317fdf2a58..6412d24d53 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -38,6 +38,13 @@ VIR_ENUM_IMPL(virDeviceAddressPCIMulti, "on", "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) { /* PCI bus has 32 slots and 8 functions per slot */ @@ -142,3 +149,58 @@ virDevicePCIAddressEqual(virDevicePCIAddress *addr1, } 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, "speed) + virBufferAsprintf(buf, " speed='%u'", lnk->speed); + if (lnk->state) + virBufferAsprintf(buf, " state='%s'", + virInterfaceStateTypeToString(lnk->state)); + virBufferAddLit(buf, "/>\n"); + return 0; +} diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index d66afd2d69..0c65a5a587 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -40,6 +40,21 @@ typedef enum { VIR_DEVICE_ADDRESS_PCI_MULTI_LAST } 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 virDevicePCIAddress *virDevicePCIAddressPtr; struct _virDevicePCIAddress { @@ -50,6 +65,13 @@ struct _virDevicePCIAddress { 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 virDevicePCIAddressParseXML(xmlNodePtr node, @@ -62,7 +84,10 @@ int virDevicePCIAddressFormat(virBufferPtr buf, bool virDevicePCIAddressEqual(virDevicePCIAddress *addr1, virDevicePCIAddress *addr2); +int virInterfaceLinkParseXML(xmlNodePtr node, + virInterfaceLinkPtr lnk); -VIR_ENUM_DECL(virDeviceAddressPCIMulti) +int virInterfaceLinkFormat(virBufferPtr buf, + const virInterfaceLink *lnk); #endif /* __DEVICE_CONF_H__ */ diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 1f67446eae..2b3f69928e 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -705,12 +705,19 @@ virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType) } def->type = type; switch (type) { - case VIR_INTERFACE_TYPE_ETHERNET: + case VIR_INTERFACE_TYPE_ETHERNET: { + xmlNodePtr lnk; + if (virInterfaceDefParseName(def, ctxt) < 0) goto error; tmp = virXPathString("string(./mac/@address)", ctxt); if (tmp != NULL) def->mac = tmp; + + lnk = virXPathNode("./link", ctxt); + if (lnk && virInterfaceLinkParseXML(lnk, &def->lnk) < 0) + goto error; + if (parentIfType == VIR_INTERFACE_TYPE_LAST) { /* only recognize these in toplevel bond interfaces */ if (virInterfaceDefParseStartMode(def, ctxt) < 0) @@ -721,6 +728,7 @@ virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType) goto error; } break; + } case VIR_INTERFACE_TYPE_BRIDGE: { xmlNodePtr bridge; @@ -1088,6 +1096,7 @@ virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def) virInterfaceStartmodeDefFormat(buf, def->startmode); if (def->mac != NULL) virBufferAsprintf(buf, "\n", def->mac); + virInterfaceLinkFormat(buf, &def->lnk); if (def->mtu != 0) virBufferAsprintf(buf, "\n", def->mtu); virInterfaceProtocolDefFormat(buf, def); diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index b3c92b2021..94c18ef022 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -31,6 +31,7 @@ # include "internal.h" # include "virutil.h" # include "virthread.h" +# include "device_conf.h" /* There is currently 3 types of interfaces */ @@ -146,6 +147,7 @@ struct _virInterfaceDef { char *name; /* interface name */ unsigned int mtu; /* maximum transmit size in byte */ char *mac; /* MAC address */ + virInterfaceLink lnk; /* interface link info */ virInterfaceStartMode startmode; /* how it is started */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d1d6ff3f99..7a740abfb1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -83,6 +83,10 @@ virDevicePCIAddressEqual; virDevicePCIAddressFormat; virDevicePCIAddressIsValid; virDevicePCIAddressParseXML; +virInterfaceLinkFormat; +virInterfaceLinkParseXML; +virInterfaceStateTypeFromString; +virInterfaceStateTypeToString; # conf/domain_addr.h diff --git a/tests/interfaceschemadata/bridge-no-address.xml b/tests/interfaceschemadata/bridge-no-address.xml index 77575349fd..68b8c94bf1 100644 --- a/tests/interfaceschemadata/bridge-no-address.xml +++ b/tests/interfaceschemadata/bridge-no-address.xml @@ -4,6 +4,7 @@ + diff --git a/tests/interfaceschemadata/bridge.xml b/tests/interfaceschemadata/bridge.xml index 2535edf94e..c865116548 100644 --- a/tests/interfaceschemadata/bridge.xml +++ b/tests/interfaceschemadata/bridge.xml @@ -7,6 +7,7 @@ + diff --git a/tests/interfaceschemadata/ethernet-dhcp.xml b/tests/interfaceschemadata/ethernet-dhcp.xml index fe969dfd6c..c124372ff1 100644 --- a/tests/interfaceschemadata/ethernet-dhcp.xml +++ b/tests/interfaceschemadata/ethernet-dhcp.xml @@ -1,6 +1,7 @@ + -- GitLab