]> xenbits.xensource.com Git - libvirt.git/commitdiff
virInterface: Expose link state & speed
authorMichal Privoznik <mprivozn@redhat.com>
Wed, 7 May 2014 12:21:35 +0000 (14:21 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 11 Jun 2014 07:13:32 +0000 (09:13 +0200)
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>
docs/schemas/basictypes.rng
docs/schemas/interface.rng
src/conf/device_conf.c
src/conf/device_conf.h
src/conf/interface_conf.c
src/conf/interface_conf.h
src/libvirt_private.syms
tests/interfaceschemadata/bridge-no-address.xml
tests/interfaceschemadata/bridge.xml
tests/interfaceschemadata/ethernet-dhcp.xml

index 34ef6137d97c7115eb4380023fa64617ad08e969..5fe3a97daeb5df370d5f3f781fd17a85dcaca0a2 100644 (file)
     </optional>
   </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>
index 3984b630a2eb409ca3acb252564f0a73ab2a0998..8e2218d1d7ff77f13db1e236ac7afdaca6c1c58a 100644 (file)
@@ -41,6 +41,7 @@
         <attribute name="address"><ref name="macAddr"/></attribute>
       </element>
     </optional>
+    <ref name="link-speed-state"/>
     <!-- FIXME: Allow (some) ethtool options -->
   </define>
 
index 317fdf2a5837b6adda117e225f0014d7cc5046c9..6412d24d537b524801cbab4a1470adb796518dca 100644 (file)
@@ -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, "<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;
+}
index d66afd2d693e4642ddd7a14238e6352e68ad0908..0c65a5a587fd922cba978e43c6ad21a81aa3f5ca 100644 (file)
@@ -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__ */
index 1f67446eae7a08bfe210ec27cfbd895838e4fc54..2b3f69928eaded6c905830d42ecb83edc9029249 100644 (file)
@@ -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, "<mac address='%s'/>\n", def->mac);
+            virInterfaceLinkFormat(buf, &def->lnk);
             if (def->mtu != 0)
                 virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
             virInterfaceProtocolDefFormat(buf, def);
index b3c92b20218d819d366a059165dc5fe8b1a0d337..94c18ef0223fa73428c95c50045f5bd9e2cfe2e5 100644 (file)
@@ -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 */
 
index d1d6ff3f994981759c8d6ba9ce9358b875a0afd3..7a740abfb1f2cb822cee4182abb3adc7b2a76d52 100644 (file)
@@ -83,6 +83,10 @@ virDevicePCIAddressEqual;
 virDevicePCIAddressFormat;
 virDevicePCIAddressIsValid;
 virDevicePCIAddressParseXML;
+virInterfaceLinkFormat;
+virInterfaceLinkParseXML;
+virInterfaceStateTypeFromString;
+virInterfaceStateTypeToString;
 
 
 # conf/domain_addr.h
index 77575349fd1a4f44af5c8aefbb1bccc94546b9b1..68b8c94bf1ca7dfc324e4d0e553459fd434b8b68 100644 (file)
@@ -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>
index 2535edf94e87f020a7ca030416fccad310dca788..c865116548216ddf87bee2e7266da6e93d5e3f6b 100644 (file)
@@ -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>
index fe969dfd6c4b61a6351230ab4c11660babc0b7d9..c124372ff1efce5fd87409320bfeb86eb212af36 100644 (file)
@@ -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'/>