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(a)redhat.com>
---
docs/schemas/interface.rng | 27 +++++++++++++++++
src/conf/interface_conf.c | 39 ++++++++++++++++++++++++-
src/conf/interface_conf.h | 15 ++++++++++
src/libvirt_private.syms | 2 ++
tests/interfaceschemadata/bridge-no-address.xml | 1 +
tests/interfaceschemadata/bridge.xml | 1 +
tests/interfaceschemadata/ethernet-dhcp.xml | 1 +
7 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/docs/schemas/interface.rng b/docs/schemas/interface.rng
index 3984b63..d980ef5 100644
--- a/docs/schemas/interface.rng
+++ b/docs/schemas/interface.rng
@@ -41,6 +41,7 @@
<attribute name="address"><ref
name="macAddr"/></attribute>
</element>
</optional>
+ <ref name="link-speed-state"/>
<!-- FIXME: Allow (some) ethtool options -->
</define>
@@ -271,6 +272,32 @@
</element>
</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>
+
+
<!--
Assignment of addresses to an interface, allowing for
different protocols
diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c
index 1f67446..227b9d9 100644
--- a/src/conf/interface_conf.c
+++ b/src/conf/interface_conf.c
@@ -31,6 +31,7 @@
#include "virxml.h"
#include "viruuid.h"
#include "virbuffer.h"
+#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_INTERFACE
@@ -38,6 +39,13 @@ VIR_ENUM_IMPL(virInterface,
VIR_INTERFACE_TYPE_LAST,
"ethernet", "bridge", "bond",
"vlan")
+VIR_ENUM_IMPL(virInterfaceState,
+ VIR_INTERFACE_STATE_LAST,
+ "" /* value of zero means no state */,
+ "unknown", "notpresent",
+ "down", "lowerlayerdown",
+ "testing", "dormant", "up")
+
static virInterfaceDefPtr
virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType);
static int
@@ -666,7 +674,7 @@ static virInterfaceDefPtr
virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
{
virInterfaceDefPtr def;
- int type;
+ int type, state;
char *tmp;
xmlNodePtr cur = ctxt->node;
@@ -711,6 +719,26 @@ virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
tmp = virXPathString("string(./mac/@address)", ctxt);
if (tmp != NULL)
def->mac = tmp;
+
+ tmp = virXPathString("string(./link/@state)", ctxt);
+ if (tmp) {
+ if ((state = virInterfaceStateTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown link state: %s"),
+ tmp);
+ goto error;
+ }
+ def->state = state;
+ }
+
+ tmp = virXPathString("string(./link/@speed)", ctxt);
+ if (tmp && virStrToLong_ul(tmp, NULL, 10, &def->speed) < 0)
{
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unable to parse link speed: %s"),
+ tmp);
+ goto error;
+ }
+
if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
/* only recognize these in toplevel bond interfaces */
if (virInterfaceDefParseStartMode(def, ctxt) < 0)
@@ -1088,6 +1116,15 @@ virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef
*def)
virInterfaceStartmodeDefFormat(buf, def->startmode);
if (def->mac != NULL)
virBufferAsprintf(buf, "<mac address='%s'/>\n",
def->mac);
+ if (def->state || def->speed) {
+ virBufferAddLit(buf, "<link");
+ if (def->speed)
+ virBufferAsprintf(buf, " speed='%lu'",
def->speed);
+ if (def->state)
+ virBufferAsprintf(buf, " state='%s'",
+ virInterfaceStateTypeToString(def->state));
+ virBufferAddLit(buf, "/>\n");
+ }
if (def->mtu != 0)
virBufferAsprintf(buf, "<mtu size='%d'/>\n",
def->mtu);
virInterfaceProtocolDefFormat(buf, def);
diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h
index b3c92b2..c8b3f6c 100644
--- a/src/conf/interface_conf.h
+++ b/src/conf/interface_conf.h
@@ -84,6 +84,19 @@ typedef enum {
VIR_INTERFACE_BOND_ARP_ALL, /* validate all */
} virInterfaceBondArpValid;
+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)
+
struct _virInterfaceDef; /* forward declaration required for bridge/bond */
typedef struct _virInterfaceBridgeDef virInterfaceBridgeDef;
@@ -146,6 +159,8 @@ struct _virInterfaceDef {
char *name; /* interface name */
unsigned int mtu; /* maximum transmit size in byte */
char *mac; /* MAC address */
+ virInterfaceState state; /* link state */
+ unsigned long speed; /* link speed in Mb per second */
virInterfaceStartMode startmode; /* how it is started */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 649da16..5e908d6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -495,6 +495,8 @@ virInterfaceObjListFree;
virInterfaceObjLock;
virInterfaceObjUnlock;
virInterfaceRemove;
+virInterfaceStateTypeFromString;
+virInterfaceStateTypeToString;
# conf/netdev_bandwidth_conf.h
diff --git a/tests/interfaceschemadata/bridge-no-address.xml
b/tests/interfaceschemadata/bridge-no-address.xml
index 7757534..68b8c94 100644
--- a/tests/interfaceschemadata/bridge-no-address.xml
+++ b/tests/interfaceschemadata/bridge-no-address.xml
@@ -4,6 +4,7 @@
<bridge stp='off'>
<interface type='ethernet' name='eth0'>
<mac address='ab:bb:cc:dd:ee:ff'/>
+ <link speed='1000' state='up'/>
</interface>
<interface type='ethernet' name='eth1'>
</interface>
diff --git a/tests/interfaceschemadata/bridge.xml b/tests/interfaceschemadata/bridge.xml
index 2535edf..c865116 100644
--- a/tests/interfaceschemadata/bridge.xml
+++ b/tests/interfaceschemadata/bridge.xml
@@ -7,6 +7,7 @@
<bridge stp='off' delay='0.01'>
<interface type='ethernet' name='eth0'>
<mac address='ab:bb:cc:dd:ee:ff'/>
+ <link speed='10'/>
</interface>
<interface type='ethernet' name='eth1'>
</interface>
diff --git a/tests/interfaceschemadata/ethernet-dhcp.xml
b/tests/interfaceschemadata/ethernet-dhcp.xml
index fe969df..c124372 100644
--- a/tests/interfaceschemadata/ethernet-dhcp.xml
+++ b/tests/interfaceschemadata/ethernet-dhcp.xml
@@ -1,6 +1,7 @@
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='aa:bb:cc:dd:ee:ff'/>
+ <link state='down'/>
<mtu size='1492'/>
<protocol family='ipv4'>
<dhcp peerdns='no'/>
--
1.9.3