netdev_bandwidth_conf.c 9.7 KB
Newer Older
1
/*
2
 * Copyright (C) 2009-2015 Red Hat, Inc.
3 4 5 6 7 8 9 10 11 12 13 14
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library.  If not, see
O
Osier Yang 已提交
16
 * <http://www.gnu.org/licenses/>.
17 18 19 20 21
 */

#include <config.h>

#include "netdev_bandwidth_conf.h"
22
#include "virerror.h"
23
#include "viralloc.h"
24
#include "virstring.h"
25 26 27 28 29 30 31 32 33 34

#define VIR_FROM_THIS VIR_FROM_NONE

static int
virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
{
    int ret = -1;
    char *average = NULL;
    char *peak = NULL;
    char *burst = NULL;
35
    char *floor = NULL;
36 37

    if (!node || !rate) {
38
        virReportError(VIR_ERR_INVALID_ARG, "%s",
39 40 41 42 43 44 45
                       _("invalid argument supplied"));
        return -1;
    }

    average = virXMLPropString(node, "average");
    peak = virXMLPropString(node, "peak");
    burst = virXMLPropString(node, "burst");
46
    floor = virXMLPropString(node, "floor");
47 48

    if (average) {
49
        if (virStrToLong_ullp(average, NULL, 10, &rate->average) < 0) {
50
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
51
                           _("could not convert bandwidth average value '%s'"),
52 53 54
                           average);
            goto cleanup;
        }
55
    } else if (!floor) {
56
        virReportError(VIR_ERR_XML_DETAIL, "%s",
57 58 59 60 61 62 63
                       _("Missing mandatory average or floor attributes"));
        goto cleanup;
    }

    if ((peak || burst) && !average) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("'peak' and 'burst' require 'average' attribute"));
64 65 66
        goto cleanup;
    }

67
    if (peak && virStrToLong_ullp(peak, NULL, 10, &rate->peak) < 0) {
68
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
69
                       _("could not convert bandwidth peak value '%s'"),
70 71 72 73
                       peak);
        goto cleanup;
    }

74
    if (burst && virStrToLong_ullp(burst, NULL, 10, &rate->burst) < 0) {
75
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
76
                       _("could not convert bandwidth burst value '%s'"),
77 78 79 80
                       burst);
        goto cleanup;
    }

81
    if (floor && virStrToLong_ullp(floor, NULL, 10, &rate->floor) < 0) {
82 83 84 85 86 87
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("could not convert bandwidth floor value '%s'"),
                       floor);
        goto cleanup;
    }

88 89
    ret = 0;

90
 cleanup:
91 92 93
    VIR_FREE(average);
    VIR_FREE(peak);
    VIR_FREE(burst);
94
    VIR_FREE(floor);
95 96 97 98 99 100

    return ret;
}

/**
 * virNetDevBandwidthParse:
101
 * @bandwidth: parsed bandwidth
102
 * @class_id: parsed class ID
103
 * @node: XML node
104
 * @allowFloor: whether "floor" setting is supported
105
 *
106
 * Parse bandwidth XML and return pointer to structure.
107 108
 * The @allowFloor attribute indicates whether the caller
 * is able to support use of the "floor" setting.
109 110 111
 *
 * Returns !NULL on success, NULL on error.
 */
112 113
int
virNetDevBandwidthParse(virNetDevBandwidthPtr *bandwidth,
114
                        unsigned int *class_id,
115
                        xmlNodePtr node,
116
                        bool allowFloor)
117
{
118
    int ret = -1;
119
    virNetDevBandwidthPtr def = NULL;
120
    xmlNodePtr cur;
121
    xmlNodePtr in = NULL, out = NULL;
122
    char *class_id_prop = NULL;
123

124
    if (VIR_ALLOC(def) < 0)
125
        return ret;
126

127
    if (!node || !virXMLNodeNameEqual(node, "bandwidth")) {
128
        virReportError(VIR_ERR_INVALID_ARG, "%s",
129
                       _("invalid argument supplied"));
130
        goto cleanup;
131 132
    }

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    class_id_prop = virXMLPropString(node, "classID");
    if (class_id_prop) {
        if (!class_id) {
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("classID attribute not supported on <bandwidth> "
                             "in this usage context"));
            goto cleanup;
        }
        if (virStrToLong_ui(class_id_prop, NULL, 10, class_id) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse class id '%s'"),
                           class_id_prop);
            goto cleanup;
        }
    }

149 150
    cur = node->children;

151 152
    while (cur) {
        if (cur->type == XML_ELEMENT_NODE) {
153
            if (virXMLNodeNameEqual(cur, "inbound")) {
154
                if (in) {
155
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
156 157
                                   _("Only one child <inbound> "
                                     "element allowed"));
158
                    goto cleanup;
159 160
                }
                in = cur;
161
            } else if (virXMLNodeNameEqual(cur, "outbound")) {
162
                if (out) {
163
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
164 165
                                   _("Only one child <outbound> "
                                     "element allowed"));
166
                    goto cleanup;
167 168 169 170 171 172 173 174 175
                }
                out = cur;
            }
            /* Silently ignore unknown elements */
        }
        cur = cur->next;
    }

    if (in) {
176
        if (VIR_ALLOC(def->in) < 0)
177
            goto cleanup;
178 179 180

        if (virNetDevBandwidthParseRate(in, def->in) < 0) {
            /* helper reported error for us */
181
            goto cleanup;
182
        }
183

184 185 186
        if (def->in->floor && !allowFloor) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("floor attribute is not supported for this config"));
187
            goto cleanup;
188
        }
189 190 191
    }

    if (out) {
192
        if (VIR_ALLOC(def->out) < 0)
193
            goto cleanup;
194 195 196

        if (virNetDevBandwidthParseRate(out, def->out) < 0) {
            /* helper reported error for us */
197
            goto cleanup;
198
        }
199 200 201 202 203

        if (def->out->floor) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("'floor' attribute allowed "
                             "only in <inbound> element"));
204
            goto cleanup;
205
        }
206 207
    }

208 209 210 211 212 213
    if (!def->in && !def->out)
        VIR_FREE(def);

    *bandwidth = def;
    def = NULL;
    ret = 0;
214

215
 cleanup:
216
    VIR_FREE(class_id_prop);
217
    virNetDevBandwidthFree(def);
218
    return ret;
219 220 221 222 223 224 225 226 227 228 229 230
}

static int
virNetDevBandwidthRateFormat(virNetDevBandwidthRatePtr def,
                             virBufferPtr buf,
                             const char *elem_name)
{
    if (!buf || !elem_name)
        return -1;
    if (!def)
        return 0;

231
    if (def->average || def->floor) {
232
        virBufferAsprintf(buf, "<%s", elem_name);
233 234 235

        if (def->average)
            virBufferAsprintf(buf, " average='%llu'", def->average);
236 237 238 239

        if (def->peak)
            virBufferAsprintf(buf, " peak='%llu'", def->peak);

240 241 242
        if (def->floor)
            virBufferAsprintf(buf, " floor='%llu'", def->floor);

243 244 245 246 247 248 249 250 251
        if (def->burst)
            virBufferAsprintf(buf, " burst='%llu'", def->burst);
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

/**
252
 * virNetDevBandwidthFormat:
253
 * @def: Data source
254
 * @class_id: the class ID to format, 0 to skip
255 256 257 258 259 260 261 262
 * @buf: Buffer to print to
 *
 * Formats bandwidth and prepend each line with @indent.
 * @buf may use auto-indentation.
 *
 * Returns 0 on success, else -1.
 */
int
263
virNetDevBandwidthFormat(const virNetDevBandwidth *def,
264 265
                         unsigned int class_id,
                         virBufferPtr buf)
266 267
{
    if (!buf)
268
        return -1;
269

270 271
    if (!def)
        return 0;
272

273 274 275 276
    virBufferAddLit(buf, "<bandwidth");
    if (class_id)
        virBufferAsprintf(buf, " classID='%u'", class_id);
    virBufferAddLit(buf, ">\n");
277
    virBufferAdjustIndent(buf, 2);
278 279
    if (virNetDevBandwidthRateFormat(def->in, buf, "inbound") < 0 ||
        virNetDevBandwidthRateFormat(def->out, buf, "outbound") < 0)
280
        return -1;
281
    virBufferAdjustIndent(buf, -2);
282 283
    virBufferAddLit(buf, "</bandwidth>\n");

284
    return 0;
285
}
286 287

void
288
virDomainClearNetBandwidth(virDomainDefPtr def)
289 290 291 292
{
    size_t i;
    virDomainNetType type;

293 294 295
    for (i = 0; i < def->nnets; i++) {
        type = virDomainNetGetActualType(def->nets[i]);
        if (virDomainNetGetActualBandwidth(def->nets[i]) &&
296
            virNetDevSupportsBandwidth(type))
297
            virNetDevBandwidthClear(def->nets[i]->ifname);
298 299
    }
}
300 301


302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
bool virNetDevSupportsBandwidth(virDomainNetType type)
{
    switch ((virDomainNetType) type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        return true;
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_UDP:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
    }
    return false;
}


325 326 327 328 329
bool
virNetDevBandwidthHasFloor(const virNetDevBandwidth *b)
{
    return b && b->in && b->in->floor != 0;
}
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349


bool virNetDevBandwidthSupportsFloor(virNetworkForwardType type)
{
    switch (type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
        return true;
    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
    case VIR_NETWORK_FORWARD_LAST:
        break;
    }
    return false;
}