[libvirt] [PATCH 1/3] lxc: refactoring LXC network definition with a sparse array.
Michal Privoznik
mprivozn at redhat.com
Mon Jan 7 14:26:58 UTC 2019
On 12/28/18 8:01 PM, Julio Faracco wrote:
> LXC was using a single data structure to define all LXC NICs. In terms
> of optimization it is very interesting, but it is not useful when you
> use a index to define networks. After major release 3.0, LXC adopted
> indexes for network definitions. So, this commit adds a sparse vector to
> handle network indexes. Now, networks can be defined in sequence using
> the legacy config. Or using a sparse array, using version 3 with indexes.
>
> Signed-off-by: Julio Faracco <jcfaracco at gmail.com>
> ---
> src/lxc/lxc_native.c | 191 ++++++++++++++++++++++++++++---------------
> 1 file changed, 124 insertions(+), 67 deletions(-)
>
> diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c
> index 1eee3fc2bb..860cf87227 100644
> --- a/src/lxc/lxc_native.c
> +++ b/src/lxc/lxc_native.c
> @@ -22,6 +22,7 @@
> #include <config.h>
>
> #include "internal.h"
> +#include "c-ctype.h"
> #include "lxc_container.h"
> #include "lxc_native.h"
> #include "util/viralloc.h"
> @@ -409,8 +410,9 @@ lxcCreateHostdevDef(int mode, int type, const char *data)
> return hostdev;
> }
>
> -typedef struct {
> - virDomainDefPtr def;
> +typedef struct _lxcNetworkParseData lxcNetworkParseData;
> +typedef lxcNetworkParseData *lxcNetworkParseDataPtr;
> +struct _lxcNetworkParseData {
> char *type;
> char *link;
> char *mac;
> @@ -422,9 +424,13 @@ typedef struct {
> size_t nips;
> char *gateway_ipv4;
> char *gateway_ipv6;
> - bool privnet;
> - size_t networks;
> -} lxcNetworkParseData;
> + size_t index;
> +};
> +
> +typedef struct {
> + lxcNetworkParseDataPtr *data;
> + int networks;
This is in fact an array and its size. For that we tend to use X name
for array and 'nX' for the size. So how about 'networks' and
'nnetworks'? Also, s/int/size_t/.
> +} lxcNetworkParseArray;
>
> static int
> lxcAddNetworkRouteDefinition(const char *address,
> @@ -464,7 +470,7 @@ lxcAddNetworkRouteDefinition(const char *address,
> }
>
> static int
> -lxcAddNetworkDefinition(lxcNetworkParseData *data)
> +lxcAddNetworkDefinition(virDomainDefPtr def, lxcNetworkParseData *data)
> {
> virDomainNetDefPtr net = NULL;
> virDomainHostdevDefPtr hostdev = NULL;
> @@ -512,9 +518,9 @@ lxcAddNetworkDefinition(lxcNetworkParseData *data)
> &hostdev->source.caps.u.net.ip.nroutes) < 0)
> goto error;
>
> - if (VIR_EXPAND_N(data->def->hostdevs, data->def->nhostdevs, 1) < 0)
> + if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0)
> goto error;
> - data->def->hostdevs[data->def->nhostdevs - 1] = hostdev;
> + def->hostdevs[def->nhostdevs - 1] = hostdev;
> } else {
> if (!(net = lxcCreateNetDef(data->type, data->link, data->mac,
> data->flag, data->macvlanmode,
> @@ -536,9 +542,9 @@ lxcAddNetworkDefinition(lxcNetworkParseData *data)
> &net->guestIP.nroutes) < 0)
> goto error;
>
> - if (VIR_EXPAND_N(data->def->nets, data->def->nnets, 1) < 0)
> + if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0)
> goto error;
> - data->def->nets[data->def->nnets - 1] = net;
> + def->nets[def->nnets - 1] = net;
> }
>
> return 1;
> @@ -552,51 +558,89 @@ lxcAddNetworkDefinition(lxcNetworkParseData *data)
> return -1;
> }
>
> +#define lxcNetworkHasIndex(entry) \
> + (STRPREFIX(entry, "lxc.net.") && c_isdigit(entry[8]))
> +
> +#define lxcNetworkIndexHasType(entry, type) \
> + (lxcNetworkHasIndex(entry) && virFileHasSuffix(entry, type))
I rather see these as inline functions.
> +
> static int
> lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
> {
> - lxcNetworkParseData *parseData = data;
> - int status;
> + lxcNetworkParseArray *parseData = data;
> + size_t index;
> +
> + /* Managing memory and indexes for version 3.0 */
> + if (lxcNetworkHasIndex(name)) {
> + sscanf(name, "lxc.net.%zu", &index);
> +
> + if (index >= parseData->networks) {
> + if (!parseData->data) {
> + if (VIR_ALLOC_N(parseData->data, index + 1) < 0)
> + return -1;
> + } else {
> + if (VIR_REALLOC_N(parseData->data, index + 1) < 0)
> + return -1;
This is allocated but released only on 'error'.
> + }
>
> - if (STREQ(name, "lxc.network.type")) {
> - virDomainDefPtr def = parseData->def;
> - size_t networks = parseData->networks;
> - bool privnet = parseData->privnet;
> + parseData->networks = index + 1;
> + }
>
> - /* Store the previous NIC */
> - status = lxcAddNetworkDefinition(parseData);
> + if (!parseData->data[index]) {
> + if (VIR_ALLOC(parseData->data[index]) < 0)
> + return -1;
> + }
> + } else {
> + /* Indexes can be 0 when a network is defined */
> + index = parseData->networks - 1;
> + }
>
> - if (status < 0)
> - return -1;
> - else if (status > 0)
> - networks++;
> - else if (parseData->type != NULL && STREQ(parseData->type, "none"))
> - privnet = false;
> + if (STREQ(name, "lxc.network.type")) {
> + /* A new NIC will be added */
> + index = parseData->networks;
>
> - /* clean NIC to store a new one */
> - memset(parseData, 0, sizeof(*parseData));
> + if (!parseData->data) {
> + if (VIR_ALLOC_N(parseData->data, index + 1) < 0)
> + return -1;
> + } else {
> + if (VIR_REALLOC_N(parseData->data, index + 1) < 0)
> + return -1;
> + }
>
> - parseData->def = def;
> - parseData->networks = networks;
> - parseData->privnet = privnet;
> + if (VIR_ALLOC(parseData->data[index]) < 0)
> + return -1;
>
> /* Keep the new value */
> - parseData->type = value->str;
> + parseData->data[index]->type = value->str;
> + parseData->data[index]->index = index;
> +
> + /* Network interface added */
> + parseData->networks++;
> }
> - else if (STREQ(name, "lxc.network.link"))
> - parseData->link = value->str;
> - else if (STREQ(name, "lxc.network.hwaddr"))
> - parseData->mac = value->str;
> - else if (STREQ(name, "lxc.network.flags"))
> - parseData->flag = value->str;
> - else if (STREQ(name, "lxc.network.macvlan.mode"))
> - parseData->macvlanmode = value->str;
> - else if (STREQ(name, "lxc.network.vlan.id"))
> - parseData->vlanid = value->str;
> - else if (STREQ(name, "lxc.network.name"))
> - parseData->name = value->str;
> - else if (STREQ(name, "lxc.network.ipv4") ||
> - STREQ(name, "lxc.network.ipv6")) {
> + else if (lxcNetworkIndexHasType(name, ".type"))
> + parseData->data[index]->type = value->str;
> + else if (STREQ(name, "lxc.network.link") ||
> + lxcNetworkIndexHasType(name, ".link"))
> + parseData->data[index]->link = value->str;
> + else if (STREQ(name, "lxc.network.hwaddr") ||
> + lxcNetworkIndexHasType(name, ".hwaddr"))
> + parseData->data[index]->mac = value->str;
> + else if (STREQ(name, "lxc.network.flags") ||
> + lxcNetworkIndexHasType(name, ".flags"))
> + parseData->data[index]->flag = value->str;
> + else if (STREQ(name, "lxc.network.macvlan.mode") ||
> + lxcNetworkIndexHasType(name, ".macvlan.mode"))
> + parseData->data[index]->macvlanmode = value->str;
> + else if (STREQ(name, "lxc.network.vlan.id") ||
> + lxcNetworkIndexHasType(name, ".vlan.id"))
> + parseData->data[index]->vlanid = value->str;
> + else if (STREQ(name, "lxc.network.name") ||
> + lxcNetworkIndexHasType(name, ".name"))
> + parseData->data[index]->name = value->str;
> + else if ((STREQ(name, "lxc.network.ipv4") ||
> + STREQ(name, "lxc.network.ipv6")) ||
> + (lxcNetworkIndexHasType(name, ".ipv4") ||
> + lxcNetworkIndexHasType(name, ".ipv6"))) {
> int family = AF_INET;
> char **ipparts = NULL;
> virNetDevIPAddrPtr ip = NULL;
> @@ -604,7 +648,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
> if (VIR_ALLOC(ip) < 0)
> return -1;
>
> - if (STREQ(name, "lxc.network.ipv6"))
> + if (STREQ(name, "lxc.network.ipv6") ||
> + lxcNetworkIndexHasType(name, ".ipv6"))
> family = AF_INET6;
>
> ipparts = virStringSplit(value->str, "/", 2);
> @@ -622,15 +667,19 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data)
>
> virStringListFree(ipparts);
>
> - if (VIR_APPEND_ELEMENT(parseData->ips, parseData->nips, ip) < 0) {
> + if (VIR_APPEND_ELEMENT(parseData->data[index]->ips,
> + parseData->data[index]->nips, ip) < 0) {
> VIR_FREE(ip);
> return -1;
> }
> - } else if (STREQ(name, "lxc.network.ipv4.gateway")) {
> - parseData->gateway_ipv4 = value->str;
> - } else if (STREQ(name, "lxc.network.ipv6.gateway")) {
> - parseData->gateway_ipv6 = value->str;
> - } else if (STRPREFIX(name, "lxc.network")) {
> + } else if (STREQ(name, "lxc.network.ipv4.gateway") ||
> + lxcNetworkIndexHasType(name, ".ipv4.gateway")) {
> + parseData->data[index]->gateway_ipv4 = value->str;
> + } else if (STREQ(name, "lxc.network.ipv6.gateway") ||
> + lxcNetworkIndexHasType(name, ".ipv6.gateway")) {
> + parseData->data[index]->gateway_ipv6 = value->str;
> + } else if (STRPREFIX(name, "lxc.network") ||
> + lxcNetworkHasIndex(name)) {
> VIR_WARN("Unhandled network property: %s = %s",
> name,
> value->str);
> @@ -645,25 +694,29 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties)
> int status;
> int result = -1;
> size_t i;
> - lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL,
> - NULL, NULL, NULL, NULL, 0,
> - NULL, NULL, true, 0};
> + bool privnet = true;
> + lxcNetworkParseArray nets = {NULL, 0};
>
> - if (virConfWalk(properties, lxcNetworkWalkCallback, &data) < 0)
> + if (virConfWalk(properties, lxcNetworkWalkCallback, &nets) < 0)
> goto error;
>
> + for (i = 0; i < nets.networks; i++) {
> + lxcNetworkParseDataPtr data = nets.data[i];
>
> - /* Add the last network definition found */
> - status = lxcAddNetworkDefinition(&data);
> + /* It needs to guarantee that index exists. */
> + /* Since there is a sparse array. */
> + if (data) {
> + /* Add network definitions */
> + status = lxcAddNetworkDefinition(def, data);
>
> - if (status < 0)
> - goto error;
> - else if (status > 0)
> - data.networks++;
> - else if (data.type != NULL && STREQ(data.type, "none"))
> - data.privnet = false;
> + if (status < 0)
> + goto error;
> + else if (data->type != NULL && STREQ(data->type, "none"))
> + privnet = false;
> + }
> + }
>
> - if (data.networks == 0 && data.privnet) {
> + if (nets.networks == 0 && privnet) {
> /* When no network type is provided LXC only adds loopback */
> def->features[VIR_DOMAIN_FEATURE_PRIVNET] = VIR_TRISTATE_SWITCH_ON;
> }
> @@ -672,9 +725,13 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties)
> return result;
>
> error:
> - for (i = 0; i < data.nips; i++)
> - VIR_FREE(data.ips[i]);
> - VIR_FREE(data.ips);
> + for (i = 0; i <= nets.networks; i++) {
There is no reason to go to including nets.networks. In fact, there
should be nothing at nets.networks index as it is past allocated array
possibly leading to a crash.
> + for (i = 0; i < nets.data[i]->nips; i++)
> + VIR_FREE(nets.data[i]->ips[i]);
> + VIR_FREE(nets.data[i]->ips);
> + }
> + for (i = 0; i <= nets.networks; i++)
> + VIR_FREE(nets.data[i]);
> return -1;
> }
>
>
The rest of the patches look okay.
Michal
More information about the libvir-list
mailing list