Re: [PATCH v3 2/2] bhyve: add e1000 nic support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 11/07/2016 09:20 AM, Roman Bogorodskiy wrote:
Recently e1000 NIC support was added to bhyve; implement that in
the bhyve driver:

  - Add capability check by analyzing output of the 'bhyve -s 0,e1000'
    command
  - Modify bhyveBuildNetArgStr() to support e1000 and also pass
    virConnectPtr so it could call bhyveDriverGetCaps() to check if this
    NIC is supported
  - Modify command parsing code to add support for e1000 and adjust tests
  - Add net-e1000 test
---
  src/bhyve/bhyve_capabilities.c                     | 27 ++++++++
  src/bhyve/bhyve_capabilities.h                     |  1 +
  src/bhyve/bhyve_command.c                          | 74 ++++++++++++++--------
  src/bhyve/bhyve_parse_command.c                    |  9 ++-
  tests/bhyveargv2xmldata/bhyveargv2xml-e1000.args   |  8 +++
  tests/bhyveargv2xmldata/bhyveargv2xml-e1000.xml    | 28 ++++++++
  .../bhyveargv2xmldata/bhyveargv2xml-virtio-net.xml |  2 +
  .../bhyveargv2xml-virtio-net4.xml                  |  1 +
  tests/bhyveargv2xmltest.c                          |  1 +
  .../bhyvexml2argvdata/bhyvexml2argv-net-e1000.args |  9 +++
  .../bhyvexml2argv-net-e1000.ldargs                 |  3 +
  .../bhyvexml2argvdata/bhyvexml2argv-net-e1000.xml  | 22 +++++++
  tests/bhyvexml2argvtest.c                          |  7 +-
  13 files changed, 162 insertions(+), 30 deletions(-)
  create mode 100644 tests/bhyveargv2xmldata/bhyveargv2xml-e1000.args
  create mode 100644 tests/bhyveargv2xmldata/bhyveargv2xml-e1000.xml
  create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.args
  create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.ldargs
  create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.xml

diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c
index be68e51..3012788 100644
--- a/src/bhyve/bhyve_capabilities.c
+++ b/src/bhyve/bhyve_capabilities.c
@@ -192,6 +192,30 @@ bhyveProbeCapsRTC_UTC(unsigned int *caps, char *binary)
      return ret;
  }
+static int
+bhyveProbeCapsNetE1000(unsigned int *caps, char *binary)
+{
+    char *error;
+    virCommandPtr cmd = NULL;
+    int ret = 0, exit;

Again, more consistent with the rest of the code to initialize ret = -1...
+
+    cmd = virCommandNew(binary);
+    virCommandAddArgList(cmd, "-s", "0,e1000", NULL);
+    virCommandSetErrorBuffer(cmd, &error);
+    if (virCommandRun(cmd, &exit) < 0) {
+        ret = -1;

...remove this line...
+        goto out;
+    }
+
+    if (strstr(error, "pci slot 0:0: unknown device \"e1000\"") == 0)

If you're going to check the return of strstr(), it's more "pure" to check "== NULL", since the return is a pointer. Or even better (and what libvirt does in most cases) change the condition into:

       if (!strstr(errror, .......))

+        *caps |= BHYVE_CAP_NET_E1000;
+
+ out:

... and change the above label to "cleanup:" with a "ret = 0;" just above it.


+    VIR_FREE(error);
+    virCommandFree(cmd);
+    return ret;
+}
+
  int
  virBhyveProbeCaps(unsigned int *caps)
  {
@@ -207,6 +231,9 @@ virBhyveProbeCaps(unsigned int *caps)
      if ((ret = bhyveProbeCapsRTC_UTC(caps, binary)))
          goto out;
+ if ((ret = bhyveProbeCapsNetE1000(caps, binary)))
+        goto out;

Following the advice from the previous patch, this will be:

             if (bhyveProbeCapsNetE1000(caps, binary) < 0)
                    goto cleanup;
+
   out:
      VIR_FREE(binary);
      return ret;
diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h
index 8e7646d..d6c7bb0 100644
--- a/src/bhyve/bhyve_capabilities.h
+++ b/src/bhyve/bhyve_capabilities.h
@@ -38,6 +38,7 @@ typedef enum {
typedef enum {
      BHYVE_CAP_RTC_UTC = 1,
+    BHYVE_CAP_NET_E1000 = 2,

Since these are bits in an int, and not values, you should make that painfully obvious like this:

               BHYVE_CAP_RTC_UTC = 1 << 0;
               BHYVE_CAP_NET_E1000 = 1 << 1;

(of course, if the future maps out like I predict, they'll eventually end up being regular incremental values anyway, so they can be used as arguments to virBitmap functions - that will be necessary as soon as you encounter "capability #33".)

  } virBhyveCapsFlags;
int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps);
diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c
index 022b03b..cfb8b45 100644
--- a/src/bhyve/bhyve_command.c
+++ b/src/bhyve/bhyve_command.c
@@ -44,7 +44,8 @@
  VIR_LOG_INIT("bhyve.bhyve_command");
static int
-bhyveBuildNetArgStr(const virDomainDef *def,
+bhyveBuildNetArgStr(virConnectPtr conn,

qemu functions tend to pass around a virQEMUCapsPtr or driver ptr rather than a conn...[*]

+                    const virDomainDef *def,
                      virDomainNetDefPtr net,
                      virCommandPtr cmd,
                      bool dryRun)
@@ -52,26 +53,46 @@ bhyveBuildNetArgStr(const virDomainDef *def,
      char macaddr[VIR_MAC_STRING_BUFLEN];
      char *realifname = NULL;
      char *brname = NULL;
+    char *nic_model = NULL;
+    int ret = -1;
      virDomainNetType actualType = virDomainNetGetActualType(net);
+ if (STREQ(net->model, "virtio")) {
+        if (VIR_STRDUP(nic_model, "virtio-net") < 0)
+            return -1;
+    } else if (STREQ(net->model, "e1000")) {

(Someday, "someone" needs to change net->model into an enum. It will involve changing things in all the hypervisor drivers though, which raises the likelyhood of "someone" breaking a hypervisor driver they aren't equipped to test :-/)

+        if ((bhyveDriverGetCaps(conn) & BHYVE_CAP_NET_E1000) != 0) {

[*]... and as a matter of fact, since bhyveDriverGetCaps execs two external binaries each time it is called, I think the capabilities should be probed at a higher level in the call chain so it's only done once for each guest that is started.

+            if (VIR_STRDUP(nic_model, "e1000") < 0)
+                return -1;
+        } else {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("NIC model 'e1000' is not supported "
+                             "by given bhyve binary"));
+            return -1;
+        }
+    } else {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("NIC model '%s' is not supported"),
+                       net->model);
+        return -1;
+    }
+
      if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
          if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)

Pre-existing condition, but you're not checking that virDomainNetGetActualBridgeName() is returning non-NULL. In the qemu and LXC drivers, that's checked while setting up interfaces, and a missing bridge name is reported. (It should have been validated during parse anyway, but....)

Also, after hearing that you're building the network driver for FreeBSD, I'm surprised that this doesn't support at least the tap-based versions of VIR_DOMAIN_NET_TYPE_NETWORK (but again, that is unrelated to the current patch).

-            return -1;
+            goto out;
      } else {
          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                         _("Network type %d is not supported"),
                         virDomainNetGetActualType(net));
-        return -1;
+        goto out;
      }
if (!net->ifname ||
          STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
          strchr(net->ifname, '%')) {
          VIR_FREE(net->ifname);
-        if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0) {
-            VIR_FREE(brname);
-            return -1;
-        }
+        if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0)
+            goto out;
      }
if (!dryRun) {
@@ -79,44 +100,41 @@ bhyveBuildNetArgStr(const virDomainDef *def,
                                             def->uuid, NULL, NULL, 0,
                                             virDomainNetGetActualVirtPortProfile(net),
                                             virDomainNetGetActualVlan(net),
-                                           VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
-            VIR_FREE(net->ifname);
-            VIR_FREE(brname);
-            return -1;
-        }
+                                           VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_PERSIST) < 0)

Since the condition is multiple lines, don't remove the braces - the hacking doc says you should use braces if either the body *or* the condition are multiple lines.

+            goto out;
realifname = virNetDevTapGetRealDeviceName(net->ifname); - if (realifname == NULL) {
-            VIR_FREE(net->ifname);
-            VIR_FREE(brname);
-            return -1;
-        }
+        if (realifname == NULL)
+            goto out;

We often/usually used "if (!realifname)" when checking for NULL pointers.

VIR_DEBUG("%s -> %s", net->ifname, realifname);
          /* hack on top of other hack: we need to set
           * interface to 'UP' again after re-opening to find its
           * name
           */
-        if (virNetDevSetOnline(net->ifname, true) != 0) {
-            VIR_FREE(realifname);
-            VIR_FREE(net->ifname);
-            VIR_FREE(brname);
-            return -1;
-        }
+        if (virNetDevSetOnline(net->ifname, true) != 0)
+            goto out;

After several of these... Not necessary this time, but for future reference (or if you want extra Brownie points this time :-)) - we've found it much easier to review patches adding new functionality if other necessary reorganization (e.g. changing all the "return -1" into "goto cleanup" and moving all resource-freeing down to cleanup:) is put in a separate prerequisite patch. Then the new functionality is just a simple addition rather than a re-org + addition.

      } else {
          if (VIR_STRDUP(realifname, "tap0") < 0)
-            return -1;
+            goto out;
      }
virCommandAddArg(cmd, "-s");
-    virCommandAddArgFormat(cmd, "%d:0,virtio-net,%s,mac=%s",
-                           net->info.addr.pci.slot,
+    virCommandAddArgFormat(cmd, "%d:0,%s,%s,mac=%s",
+                           net->info.addr.pci.slot, nic_model,
                             realifname, virMacAddrFormat(&net->mac, macaddr));
+
+    ret = 0;
+ out:

Change this label to "cleanup:".

+    VIR_FREE(net->ifname);
+    VIR_FREE(realifname);
+    VIR_FREE(brname);
      VIR_FREE(realifname);
+    VIR_FREE(nic_model);
- return 0;
+    return ret;
  }
static int
@@ -284,7 +302,7 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn,
      /* Devices */
      for (i = 0; i < def->nnets; i++) {
          virDomainNetDefPtr net = def->nets[i];
-        if (bhyveBuildNetArgStr(def, net, cmd, dryRun) < 0)
+        if (bhyveBuildNetArgStr(conn, def, net, cmd, dryRun) < 0)


Again, rather than passing down conn here, the capabilities should have been probed either here or higher, and then just the capabilities sent down to lower levels.


              goto error;
      }
      for (i = 0; i < def->ndisks; i++) {
diff --git a/src/bhyve/bhyve_parse_command.c b/src/bhyve/bhyve_parse_command.c
index 0ae7a83..deb3d96 100644
--- a/src/bhyve/bhyve_parse_command.c
+++ b/src/bhyve/bhyve_parse_command.c
@@ -496,6 +496,7 @@ bhyveParsePCINet(virDomainDefPtr def,
                   unsigned pcislot,
                   unsigned pcibus,
                   unsigned function,
+                 const char *model,
                   const char *config)
  {
      /* -s slot,virtio-net,tapN[,mac=xx:xx:xx:xx:xx:xx] */
@@ -510,6 +511,8 @@ bhyveParsePCINet(virDomainDefPtr def,
      /* Let's just assume it is VIR_DOMAIN_NET_TYPE_ETHERNET, it could also be
       * a bridge, but this is the most generic option. */

(Preexisting, but...) That's an odd choice, since the bhyve driver only supports VIR_DOMAIN_NET_TYPE_BRIDGE. So you're guaranteeing that the config you generate will be unusable.

      net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+    if (VIR_STRDUP(net->model, model) < 0)
+        goto error;
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
      net->info.addr.pci.slot = pcislot;
@@ -617,7 +620,11 @@ bhyveParseBhyvePCIArg(virDomainDefPtr def,
                            nahcidisk,
                            conf);
      else if (STREQ(emulation, "virtio-net"))
-        bhyveParsePCINet(def, xmlopt, caps, pcislot, bus, function, conf);
+        bhyveParsePCINet(def, xmlopt, caps, pcislot, bus, function,
+                         "virtio", conf);
+    else if (STREQ(emulation, "e1000"))
+        bhyveParsePCINet(def, xmlopt, caps, pcislot, bus, function,
+                         "e1000", conf);
VIR_FREE(emulation);
      VIR_FREE(slotdef);
diff --git a/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.args b/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.args
new file mode 100644
index 0000000..aa568fe
--- /dev/null
+++ b/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.args
@@ -0,0 +1,8 @@
+/usr/sbin/bhyve \
+-c 1 \
+-m 214 \
+-H \
+-P \
+-s 0:0,hostbridge \
+-s 1:0,e1000,tap0 \
+-s 1:1,e1000,tap1,mac=FE:ED:AD:EA:DF:15 bhyve
diff --git a/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.xml b/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.xml
new file mode 100644
index 0000000..cd1ec5d
--- /dev/null
+++ b/tests/bhyveargv2xmldata/bhyveargv2xml-e1000.xml
@@ -0,0 +1,28 @@
+<domain type='bhyve'>
+  <name>bhyve</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type>hvm</type>
+  </os>
+  <clock offset='localtime'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>destroy</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <interface type='ethernet'>
+      <mac address='52:54:00:00:00:00'/>
+      <target dev='tap0'/>
+      <model type='e1000'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+    </interface>
+    <interface type='ethernet'>
+      <mac address='fe:ed:ad:ea:df:15'/>
+      <target dev='tap1'/>
+      <model type='e1000'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </interface>
+  </devices>
+</domain>
diff --git a/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net.xml b/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net.xml
index 09cc79b..d920a09 100644
--- a/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net.xml
+++ b/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net.xml
@@ -15,11 +15,13 @@
      <interface type='ethernet'>
        <mac address='52:54:00:00:00:00'/>
        <target dev='tap0'/>
+      <model type='virtio'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
      </interface>
      <interface type='ethernet'>
        <mac address='fe:ed:ad:ea:df:15'/>
        <target dev='tap1'/>
+      <model type='virtio'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
      </interface>
    </devices>
diff --git a/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net4.xml b/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net4.xml
index e1bda46..6fbb3d2 100644
--- a/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net4.xml
+++ b/tests/bhyveargv2xmldata/bhyveargv2xml-virtio-net4.xml
@@ -15,6 +15,7 @@
      <interface type='ethernet'>
        <mac address='00:00:00:00:00:00'/>
        <target dev='tap1'/>
+      <model type='virtio'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
      </interface>
    </devices>
diff --git a/tests/bhyveargv2xmltest.c b/tests/bhyveargv2xmltest.c
index 0995f69..e759e4f 100644
--- a/tests/bhyveargv2xmltest.c
+++ b/tests/bhyveargv2xmltest.c
@@ -175,6 +175,7 @@ mymain(void)
      DO_TEST("ahci-hd");
      DO_TEST("virtio-blk");
      DO_TEST("virtio-net");
+    DO_TEST("e1000");
      DO_TEST_WARN("virtio-net2");
      DO_TEST_WARN("virtio-net3");
      DO_TEST_WARN("virtio-net4");
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.args b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.args
new file mode 100644
index 0000000..cd0e896
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.args
@@ -0,0 +1,9 @@
+/usr/sbin/bhyve \
+-c 1 \
+-m 214 \
+-u \
+-H \
+-P \
+-s 0:0,hostbridge \
+-s 3:0,e1000,faketapdev,mac=52:54:00:00:00:00 \
+-s 2:0,ahci-hd,/tmp/freebsd.img bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.ldargs b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.ldargs
new file mode 100644
index 0000000..32538b5
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.ldargs
@@ -0,0 +1,3 @@
+/usr/sbin/bhyveload \
+-m 214 \
+-d /tmp/freebsd.img bhyve
diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.xml
new file mode 100644
index 0000000..4b3148c
--- /dev/null
+++ b/tests/bhyvexml2argvdata/bhyvexml2argv-net-e1000.xml
@@ -0,0 +1,22 @@
+<domain type='bhyve'>
+  <name>bhyve</name>
+  <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
+  <memory>219136</memory>
+  <vcpu>1</vcpu>
+  <os>
+    <type>hvm</type>
+  </os>
+  <devices>
+    <disk type='file'>
+      <driver name='file' type='raw'/>
+      <source file='/tmp/freebsd.img'/>
+      <target dev='hda' bus='sata'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </disk>
+    <interface type='bridge'>
+      <model type='e1000'/>
+      <source bridge="virbr0"/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </interface>
+  </devices>
+</domain>
diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c
index b85439b..a92b0cf 100644
--- a/tests/bhyvexml2argvtest.c
+++ b/tests/bhyvexml2argvtest.c
@@ -151,7 +151,7 @@ mymain(void)
      DO_TEST_FULL(name, FLAG_EXPECT_PARSE_ERROR)
driver.grubcaps = BHYVE_GRUB_CAP_CONSDEV;
-    driver.bhyvecaps = BHYVE_CAP_RTC_UTC;
+    driver.bhyvecaps = BHYVE_CAP_RTC_UTC | BHYVE_CAP_NET_E1000;
DO_TEST("base");
      DO_TEST("acpiapic");
@@ -174,11 +174,16 @@ mymain(void)
      DO_TEST("disk-cdrom-grub");
      DO_TEST("serial-grub");
      DO_TEST("localtime");
+    DO_TEST("net-e1000");
driver.grubcaps = 0; DO_TEST("serial-grub-nocons"); + driver.bhyvecaps &= ~BHYVE_CAP_NET_E1000;
+
+    DO_TEST_FAILURE("net-e1000");
+
      virObjectUnref(driver.caps);
      virObjectUnref(driver.xmlopt);


(I'll trust that the test cases are correct, since I don't know what bhyve commands look like :-)


--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]