LXC network devices can now be assigned a custom NIC device name on the container side. For example, this is configured with: <interface type='network'> <source network='default'/> <guest dev="eth1"/> </interface> In this example the network card will appear as eth1 in the guest. --- docs/schemas/domaincommon.rng | 17 +++++++++++++++++ src/conf/domain_conf.c | 27 +++++++++++++++++++++++++++ src/conf/domain_conf.h | 2 ++ src/lxc/lxc_container.c | 29 +++++++++++++++++++++++++---- src/lxc/lxc_process.c | 25 +++++++++++++++++++++++++ tests/lxcxml2xmldata/lxc-idmap.xml | 1 + 6 files changed, 97 insertions(+), 4 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 33d0308..e7ca992 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2165,6 +2165,23 @@ </element> </optional> <optional> + <element name="guest"> + <interleave> + <optional> + <attribute name="dev"> + <ref name="deviceName"/> + </attribute> + </optional> + <optional> + <attribute name="actual"> + <ref name="deviceName"/> + </attribute> + </optional> + </interleave> + <empty/> + </element> + </optional> + <optional> <element name="mac"> <attribute name="address"> <ref name="uniMacAddr"/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b7aa4f5..5cd6ae6 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1383,6 +1383,8 @@ void virDomainNetDefFree(virDomainNetDefPtr def) VIR_FREE(def->virtPortProfile); VIR_FREE(def->script); VIR_FREE(def->ifname); + VIR_FREE(def->ifname_guest); + VIR_FREE(def->ifname_guest_actual); virDomainDeviceInfoClear(&def->info); @@ -6618,6 +6620,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, char *bridge = NULL; char *dev = NULL; char *ifname = NULL; + char *ifname_guest = NULL; + char *ifname_guest_actual = NULL; char *script = NULL; char *address = NULL; char *port = NULL; @@ -6723,6 +6727,10 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, /* An auto-generated target name, blank it out */ VIR_FREE(ifname); } + } else if ((!ifname_guest || !ifname_guest_actual) && + xmlStrEqual(cur->name, BAD_CAST "guest")) { + ifname_guest = virXMLPropString(cur, "dev"); + ifname_guest_actual = virXMLPropString(cur, "actual"); } else if (!linkstate && xmlStrEqual(cur->name, BAD_CAST "link")) { linkstate = virXMLPropString(cur, "state"); @@ -6964,6 +6972,14 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, def->ifname = ifname; ifname = NULL; } + if (ifname_guest != NULL) { + def->ifname_guest = ifname_guest; + ifname_guest = NULL; + } + if (ifname_guest_actual != NULL) { + def->ifname_guest_actual = ifname_guest_actual; + ifname_guest_actual = NULL; + } /* NIC model (see -net nic,model=?). We only check that it looks * reasonable, not that it is a supported NIC type. FWIW kvm @@ -15883,6 +15899,17 @@ virDomainNetDefFormat(virBufferPtr buf, /* Skip auto-generated target names for inactive config. */ virBufferEscapeString(buf, "<target dev='%s'/>\n", def->ifname); } + if (def->ifname_guest || def->ifname_guest_actual) { + virBufferAddLit(buf, "<guest"); + /* Skip auto-generated target names for inactive config. */ + if (def->ifname_guest) + virBufferEscapeString(buf, " dev='%s'", def->ifname_guest); + + /* Only set if the host is running, so shouldn't pollute output */ + if (def->ifname_guest_actual) + virBufferEscapeString(buf, " actual='%s'", def->ifname_guest_actual); + virBufferAddLit(buf, "/>\n"); + } if (def->model) { virBufferEscapeString(buf, "<model type='%s'/>\n", def->model); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 1122eb2..60aa491 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -915,6 +915,8 @@ struct _virDomainNetDef { } tune; char *script; char *ifname; + char *ifname_guest; + char *ifname_guest_actual; virDomainDeviceInfo info; char *filter; virNWFilterHashTablePtr filterparams; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index fd8ab16..c7423db 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -464,6 +464,21 @@ static int lxcContainerSetID(virDomainDefPtr def) } +static virDomainNetDefPtr +lxcContainerGetNetDef(virDomainDefPtr vmDef, const char *devName) +{ + size_t i; + virDomainNetDefPtr netDef; + + for (i = 0; i < vmDef->nnets; i++) { + netDef = vmDef->nets[i]; + if (STREQ(netDef->ifname_guest_actual, devName)) + return netDef; + } + + return NULL; +} + /** * lxcContainerRenameAndEnableInterfaces: * @nveths: number of interfaces @@ -475,16 +490,23 @@ static int lxcContainerSetID(virDomainDefPtr def) * * Returns 0 on success or nonzero in case of error */ -static int lxcContainerRenameAndEnableInterfaces(bool privNet, +static int lxcContainerRenameAndEnableInterfaces(virDomainDefPtr vmDef, size_t nveths, char **veths) { int rc = 0; size_t i; char *newname = NULL; + virDomainNetDefPtr netDef; + bool privNet = vmDef->features[VIR_DOMAIN_FEATURE_PRIVNET] == + VIR_DOMAIN_FEATURE_STATE_ON; for (i = 0; i < nveths; i++) { - if (virAsprintf(&newname, "eth%zu", i) < 0) { + if (!(netDef = lxcContainerGetNetDef(vmDef, veths[i]))) + return -1; + + newname = netDef->ifname_guest; + if (!newname) { rc = -1; goto error_out; } @@ -1866,8 +1888,7 @@ static int lxcContainerChild(void *data) } /* rename and enable interfaces */ - if (lxcContainerRenameAndEnableInterfaces(vmDef->features[VIR_DOMAIN_FEATURE_PRIVNET] == - VIR_DOMAIN_FEATURE_STATE_ON, + if (lxcContainerRenameAndEnableInterfaces(vmDef, argv->nveths, argv->veths) < 0) { goto cleanup; diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 0aef13a..d532e20 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -259,6 +259,8 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn, if (virNetDevSetMAC(containerVeth, &net->mac) < 0) goto cleanup; + if (VIR_STRDUP(net->ifname_guest_actual, containerVeth) < 0) + goto cleanup; if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) { if (virNetDevOpenvswitchAddPort(brname, parentVeth, &net->mac, @@ -369,6 +371,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, { int ret = -1; size_t i; + size_t niface = 0; for (i = 0; i < def->nnets; i++) { char *veth = NULL; @@ -451,6 +454,13 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, } (*veths)[(*nveths)-1] = veth; + + /* Make sure all net definitions will have a name in the container */ + if (!def->nets[i]->ifname_guest) { + if (virAsprintf(&def->nets[i]->ifname_guest, "eth%zu", niface) < 0) + return -1; + niface++; + } } ret = 0; @@ -470,6 +480,18 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, return ret; } +static void +virLXCProcessCleanInterfaces(virDomainDefPtr def) +{ + size_t i; + + for (i = 0; i < def->nnets; i++) { + VIR_FREE(def->nets[i]->ifname_guest_actual); + def->nets[i]->ifname_guest_actual = NULL; + VIR_DEBUG("Cleared net names: %s", def->nets[i]->ifname_guest); + } +} + extern virLXCDriverPtr lxc_driver; static void virLXCProcessMonitorEOFNotify(virLXCMonitorPtr mon, @@ -1306,6 +1328,9 @@ int virLXCProcessStart(virConnectPtr conn, vm, false) < 0) goto error; + /* We don't need the temporary NIC names anymore, clear them */ + virLXCProcessCleanInterfaces(vm->def); + /* Write domain status to disk. * * XXX: Earlier we wrote the plain "live" domain XML to this diff --git a/tests/lxcxml2xmldata/lxc-idmap.xml b/tests/lxcxml2xmldata/lxc-idmap.xml index 3cced21..946d363 100644 --- a/tests/lxcxml2xmldata/lxc-idmap.xml +++ b/tests/lxcxml2xmldata/lxc-idmap.xml @@ -29,6 +29,7 @@ <mac address='00:16:3e:0f:ef:8a'/> <source bridge='bri0'/> <target dev='veth0'/> + <guest dev='eth2'/> </interface> <console type='pty'> <target type='lxc' port='0'/> -- 1.8.4.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list