[libvirt] [PATCH v1 09/11] network: Allow class ID to be reused
Laine Stump
laine at laine.org
Fri Nov 30 20:55:01 UTC 2012
On 11/19/2012 11:51 AM, Michal Privoznik wrote:
> With current implementation, class ID is just incremented. This can
> lead to its exhaustion as tc accepts only 16 bits long identifiers.
> Hence, it's better if we allow class ID to be reused. To keep track
> which IDs are free and which are taken virBitmap is used. This requires
> network status file to change a bit: from <class_id next="5"/> to
> <class_id bitmap="0-4"/>. But since the previous format hasn't been
> released, it doesn't really matter.
Heh. Well, there you have it. :-) You've already implemented what I
suggested in the review of 5/10. But rather than introducing one
implementation that we need to review, then almost immediately replacing
it with something else, why not just implement it this way to begin with?
> ---
> src/conf/network_conf.c | 34 +++++++++++++++++++++++++----
> src/conf/network_conf.h | 3 +-
> src/network/bridge_driver.c | 49 ++++++++++++++++++++++++++++++++++++-------
> 3 files changed, 72 insertions(+), 14 deletions(-)
>
> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
> index 9c2e4d4..a41119c 100644
> --- a/src/conf/network_conf.c
> +++ b/src/conf/network_conf.c
> @@ -47,6 +47,8 @@
>
> #define MAX_BRIDGE_ID 256
> #define VIR_FROM_THIS VIR_FROM_NETWORK
> +/* currently, /sbin/tc implementation allows up 16 bits for minor class size */
> +#define CLASS_ID_BITMAP_SIZE (1<<16)
>
> VIR_ENUM_IMPL(virNetworkForward,
> VIR_NETWORK_FORWARD_LAST,
> @@ -317,13 +319,29 @@ virNetworkAssignDef(virNetworkObjListPtr nets,
> return NULL;
> }
> virNetworkObjLock(network);
> - network->def = def;
> - network->class_id = 3; /* next free class id */
>
> + if (!(network->class_id = virBitmapNew(CLASS_ID_BITMAP_SIZE))) {
> + virReportOOMError();
> + goto error;
> + }
> +
> + if (virBitmapSetBit(network->class_id, 0) < 0 ||
> + virBitmapSetBit(network->class_id, 1) < 0 ||
> + virBitmapSetBit(network->class_id, 2) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("unable to initialize class id bitmap"));
> + goto error;
> + }
> +
> + network->def = def;
> nets->objs[nets->count] = network;
> nets->count++;
>
> return network;
> +error:
> + virNetworkObjUnlock(network);
> + virNetworkObjFree(network);
> + return NULL;
>
> }
>
> @@ -1673,9 +1691,10 @@ virNetworkObjUpdateParseFile(const char *filename,
> char *floor_sum = NULL;
>
> ctxt->node = node;
> - class_id = virXPathString("string(./class_id[1]/@next)", ctxt);
> + class_id = virXPathString("string(./class_id[1]/@bitmap)", ctxt);
> if (class_id &&
> - virStrToLong_ui(class_id, NULL, 10, &net->class_id) < 0) {
> + virBitmapParse(class_id, ',',
> + &net->class_id, CLASS_ID_BITMAP_SIZE) < 0) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> _("Malformed 'class_id' attribute: %s"),
> class_id);
> @@ -2054,10 +2073,15 @@ virNetworkObjFormat(virNetworkObjPtr net,
> unsigned int flags)
> {
> virBuffer buf = VIR_BUFFER_INITIALIZER;
> + char *class_id = virBitmapFormat(net->class_id);
> +
> + if (!class_id)
> + goto no_memory;
>
> virBufferAddLit(&buf, "<networkstatus>\n");
> - virBufferAsprintf(&buf, " <class_id next='%u'/>\n", net->class_id);
> + virBufferAsprintf(&buf, " <class_id bitmap='%s'/>\n", class_id);
> virBufferAsprintf(&buf, " <floor sum='%llu'/>\n", net->floor_sum);
> + VIR_FREE(class_id);
>
> virBufferAdjustIndent(&buf, 2);
> if (virNetworkDefFormatInternal(&buf, net->def, flags) < 0)
> diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
> index efa9dea..6f6b221 100644
> --- a/src/conf/network_conf.h
> +++ b/src/conf/network_conf.h
> @@ -38,6 +38,7 @@
> # include "virnetdevvlan.h"
> # include "virmacaddr.h"
> # include "device_conf.h"
> +# include "bitmap.h"
>
> enum virNetworkForwardType {
> VIR_NETWORK_FORWARD_NONE = 0,
> @@ -222,7 +223,7 @@ struct _virNetworkObj {
> virNetworkDefPtr def; /* The current definition */
> virNetworkDefPtr newDef; /* New definition to activate at shutdown */
>
> - unsigned int class_id; /* next class ID for QoS */
> + virBitmapPtr class_id; /* bitmap of class IDs for QoS */
> unsigned long long floor_sum; /* sum of all 'floor'-s of attached NICs */
> };
>
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
> index 5a0f43f..8341a78 100644
> --- a/src/network/bridge_driver.c
> +++ b/src/network/bridge_driver.c
> @@ -4249,6 +4249,31 @@ cleanup:
> return ret;
> }
>
> +/**
> + * networkNextClassID:
> + * @net: network object
> + *
> + * Find next free class ID. @net is supposed
> + * to be locked already. If there is a free ID,
> + * it is marked as used and returned.
> + *
> + * Returns next free class ID or -1 if none is available.
> + */
> +static ssize_t
> +networkNextClassID(virNetworkObjPtr net)
> +{
> + size_t ret = 0;
> + bool is_set = false;
> +
> + while (virBitmapGetBit(net->class_id, ret, &is_set) == 0 && is_set)
> + ret++;
> +
> + if (is_set || virBitmapSetBit(net->class_id, ret) < 0)
> + return -1;
> +
> + return ret;
> +}
> +
> int
> networkNotifyPlug(virNetworkPtr network,
> virDomainNetDefPtr iface)
> @@ -4258,6 +4283,7 @@ networkNotifyPlug(virNetworkPtr network,
> int ret = -1;
> int plug_ret;
> unsigned long long new_rate = 0;
> + ssize_t class_id = 0;
>
> networkDriverLock(driver);
> net = virNetworkFindByUUID(&driver->networks, network->uuid);
> @@ -4274,15 +4300,21 @@ networkNotifyPlug(virNetworkPtr network,
> goto cleanup;
> }
>
> + /* generate new class_id */
> + if ((class_id = networkNextClassID(net)) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Could not generate next class ID"));
> + goto cleanup;
> + }
> +
> plug_ret = virNetDevBandwidthPlug(net->def->bridge,
> net->def->bandwidth,
> iface->ifname,
> &iface->mac,
> iface->bandwidth,
> - net->class_id);
> + class_id);
> if (plug_ret < 0) {
> - ignore_value(virNetDevBandwidthUnplug(net->def->bridge,
> - net->class_id));
> + ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
> goto cleanup;
> }
>
> @@ -4296,17 +4328,15 @@ networkNotifyPlug(virNetworkPtr network,
> }
>
> /* QoS was set, generate new class ID */
> - iface->class_id = net->class_id;
> - net->class_id++;
> + iface->class_id = class_id;
> /* update sum of 'floor'-s of attached NICs */
> net->floor_sum += iface->bandwidth->in->floor;
> /* update status file */
> if (virNetworkSaveStatus(NETWORK_STATE_DIR, net) < 0) {
> - net->class_id--;
> + ignore_value(virBitmapClearBit(net->class_id, class_id));
> net->floor_sum -= iface->bandwidth->in->floor;
> iface->class_id = 0;
> - ignore_value(virNetDevBandwidthUnplug(net->def->bridge,
> - net->class_id));
> + ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
> goto cleanup;
> }
> /* update rate for non guaranteed NICs */
> @@ -4348,9 +4378,12 @@ networkNotifyUnplug(virDomainNetDefPtr iface)
> goto cleanup;
> /* update sum of 'floor'-s of attached NICs */
> net->floor_sum -= iface->bandwidth->in->floor;
> + /* return class ID */
> + ignore_value(virBitmapClearBit(net->class_id, iface->class_id));
> /* update status file */
> if (virNetworkSaveStatus(NETWORK_STATE_DIR, net) < 0) {
> net->floor_sum += iface->bandwidth->in->floor;
> + ignore_value(virBitmapSetBit(net->class_id, iface->class_id));
> goto cleanup;
> }
> /* update rate for non guaranteed NICs */
More information about the libvir-list
mailing list