case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
case VIR_DOMAIN_NET_TYPE_DIRECT:
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
virBufferAsprintf(&buf, "tap%c", type_sep);
/* for one tapfd 'fd=' shall be used,
* for more than one 'fds=' is the right choice */
is_tap = true;
break;
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- virBufferAddLit(&buf, "tap");
- if (net->ifname) {
- virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
- type_sep = ',';
- }
- if (net->script) {
- virBufferAsprintf(&buf, "%cscript=%s", type_sep,
- net->script);
- type_sep = ',';
- }
- is_tap = true;
- break;
-
case VIR_DOMAIN_NET_TYPE_CLIENT:
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
type_sep,
if (net->driver.virtio.queues > 0 &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
- actualType == VIR_DOMAIN_NET_TYPE_DIRECT)) {
+ actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Multiqueue network is not supported for: %s"),
virDomainNetTypeToString(actualType));
/* and only TAP devices support nwfilter rules */
if (net->filter &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("filterref is not supported for "
"network interfaces of type %s"),
if (net->backend.tap &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Custom tap device path is not supported for: %s"),
virDomainNetTypeToString(actualType));
if (qemuInterfaceDirectConnect(def, driver, net,
tapfd, tapfdSize, vmop) < 0)
goto cleanup;
+ } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
+ tapfdSize = net->driver.virtio.queues;
+ if (!tapfdSize)
+ tapfdSize = 1;
+
+ if (VIR_ALLOC_N(tapfd, tapfdSize) < 0 ||
+ VIR_ALLOC_N(tapfdName, tapfdSize) < 0)
+ goto cleanup;
+
+ memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
+
+ if (qemuInterfaceEthernetConnect(def, driver, net,
+ tapfd, tapfdSize) < 0)
+ goto cleanup;
}
/* For types whose implementations use a netdev on the host, add
if (net->driver.virtio.queues > 0 &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
- actualType == VIR_DOMAIN_NET_TYPE_DIRECT)) {
+ actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Multiqueue network is not supported for: %s"),
virDomainNetTypeToString(actualType));
/* and only TAP devices support nwfilter rules */
if (net->filter &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("filterref is not supported for "
"network interfaces of type %s"),
vhostfd, &vhostfdSize) < 0)
goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
- vhostfdSize = 1;
- if (VIR_ALLOC(vhostfd) < 0)
+ tapfdSize = vhostfdSize = net->driver.virtio.queues;
+ if (!tapfdSize)
+ tapfdSize = vhostfdSize = 1;
+ if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
goto cleanup;
- *vhostfd = -1;
+ memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
+ if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
+ goto cleanup;
+ memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
+ if (qemuInterfaceEthernetConnect(vm->def, driver, net,
+ tapfd, tapfdSize) < 0)
+ goto cleanup;
+ iface_connected = true;
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
vhostfd, &vhostfdSize) < 0)
goto cleanup;
if (ret < 0)
goto cleanup;
+ if (virDomainNetGetActualType(dev) == VIR_DOMAIN_NET_TYPE_ETHERNET) {
+ switch (linkstate) {
+ case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP:
+ case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT:
+ if ((ret = virNetDevSetOnline(dev->ifname, true)) < 0)
+ goto cleanup;
+ break;
+
+ case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN:
+ if ((ret = virNetDevSetOnline(dev->ifname, false)) < 0)
+ goto cleanup;
+ break;
+ }
+ }
+
/* modify the device configuration */
dev->linkstate = linkstate;
return *tapfd < 0 ? -1 : 0;
}
+/**
+ * qemuExecuteEthernetScript:
+ * @ifname: the interface name
+ * @script: the script name
+ *
+ * This function executes script for new tap device created by libvirt.
+ * Returns 0 in case of success or -1 on failure
+ */
+static int
+qemuExecuteEthernetScript(const char *ifname, const char *script)
+{
+ virCommandPtr cmd;
+ int ret;
+
+ cmd = virCommandNew(script);
+ virCommandAddArgFormat(cmd, "%s", ifname);
+ virCommandClearCaps(cmd);
+#ifdef CAP_NET_ADMIN
+ virCommandAllowCap(cmd, CAP_NET_ADMIN);
+#endif
+ virCommandAddEnvPassCommon(cmd);
+
+ ret = virCommandRun(cmd, NULL);
+
+ virCommandFree(cmd);
+ return ret;
+}
+
+/* qemuInterfaceEthernetConnect:
+ * @def: the definition of the VM
+ * @driver: qemu driver data
+ * @net: pointer to the VM's interface description
+ * @tapfd: array of file descriptor return value for the new device
+ * @tapfdsize: number of file descriptors in @tapfd
+ *
+ * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_ETHERNET
+ * (i.e. if the connection is made with a tap device)
+ */
+int
+qemuInterfaceEthernetConnect(virDomainDefPtr def,
+ virQEMUDriverPtr driver,
+ virDomainNetDefPtr net,
+ int *tapfd,
+ size_t tapfdSize)
+{
+ virMacAddr tapmac;
+ int ret = -1;
+ unsigned int tap_create_flags = VIR_NETDEV_TAP_CREATE_IFUP;
+ bool template_ifname = false;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ const char *tunpath = "/dev/net/tun";
+
+ if (net->backend.tap) {
+ tunpath = net->backend.tap;
+ if (!virQEMUDriverIsPrivileged(driver)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("cannot use custom tap device in session mode"));
+ goto cleanup;
+ }
+ }
+
+ 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)
+ goto cleanup;
+ /* avoid exposing vnet%d in getXMLDesc or error outputs */
+ template_ifname = true;
+ }
+
+ if (net->model && STREQ(net->model, "virtio"))
+ tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
+
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, tapfdSize,
+ tap_create_flags) < 0) {
+ virDomainAuditNetDevice(def, net, tunpath, false);
+ goto cleanup;
+ }
+
+ virDomainAuditNetDevice(def, net, tunpath, true);
+ virMacAddrSet(&tapmac, &net->mac);
+ tapmac.addr[0] = 0xFE;
+
+ if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
+ goto cleanup;
+
+ if (net->script &&
+ qemuExecuteEthernetScript(net->ifname, net->script) < 0)
+ goto cleanup;
+
+ if (cfg->macFilter &&
+ ebtablesAddForwardAllowIn(driver->ebtables,
+ net->ifname,
+ &net->mac) < 0)
+ goto cleanup;
+
+ if (net->filter &&
+ virDomainConfNWFilterInstantiate(def->uuid, net) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (ret < 0) {
+ size_t i;
+ for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
+ VIR_FORCE_CLOSE(tapfd[i]);
+ if (template_ifname)
+ VIR_FREE(net->ifname);
+ }
+ virObjectUnref(cfg);
+
+ return ret;
+}
+
+
/* qemuInterfaceBridgeConnect:
* @def: the definition of the VM
* @driver: qemu driver data
int *tapfd,
size_t tapfdSize,
virNetDevVPortProfileOp vmop);
+int qemuInterfaceEthernetConnect(virDomainDefPtr def,
+ virQEMUDriverPtr driver,
+ virDomainNetDefPtr net,
+ int *tapfd,
+ size_t tapfdSize);
int qemuInterfaceBridgeConnect(virDomainDefPtr def,
virQEMUDriverPtr driver,
virDomainNetGetActualVirtPortProfile(net),
cfg->stateDir));
break;
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (net->ifname) {
+ ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
+ VIR_FREE(net->ifname);
+ }
+ break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP