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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list