interface_conf.c 37.4 KB
Newer Older
1 2 3
/*
 * interface_conf.c: interfaces XML handling
 *
4
 * Copyright (C) 2006-2010, 2013, 2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24
 *
 * Author: Daniel Veillard <veillard@redhat.com>
 *         Laine Stump <laine@redhat.com>
 */

#include <config.h>
25
#include "virerror.h"
26 27 28 29
#include "datatypes.h"

#include "interface_conf.h"

30
#include "viralloc.h"
31
#include "virxml.h"
32
#include "viruuid.h"
33
#include "virbuffer.h"
34 35 36 37 38

#define VIR_FROM_THIS VIR_FROM_INTERFACE

VIR_ENUM_IMPL(virInterface,
              VIR_INTERFACE_TYPE_LAST,
39
              "ethernet", "bridge", "bond", "vlan")
40

41
static virInterfaceDefPtr
42
virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType);
43
static int
44
virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def);
45

46
static
47 48
void virInterfaceIpDefFree(virInterfaceIpDefPtr def)
{
49 50 51
    if (def == NULL)
        return;
    VIR_FREE(def->address);
52
    VIR_FREE(def);
53 54 55
}

static
56 57
void virInterfaceProtocolDefFree(virInterfaceProtocolDefPtr def)
{
58
    size_t i;
59 60 61

    if (def == NULL)
        return;
62 63
    for (i = 0; i < def->nips; i++) {
        virInterfaceIpDefFree(def->ips[i]);
64 65 66 67 68 69 70
    }
    VIR_FREE(def->ips);
    VIR_FREE(def->family);
    VIR_FREE(def->gateway);
    VIR_FREE(def);
}

71 72
void virInterfaceDefFree(virInterfaceDefPtr def)
{
73 74
    size_t i;
    int pp;
75 76 77 78 79 80 81 82 83

    if (def == NULL)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->mac);

    switch (def->type) {
        case VIR_INTERFACE_TYPE_BRIDGE:
84
            VIR_FREE(def->data.bridge.delay);
85
            for (i = 0; i < def->data.bridge.nbItf; i++) {
86
                if (def->data.bridge.itf[i] == NULL)
87
                    break; /* to cope with half parsed data on errors */
88
                virInterfaceDefFree(def->data.bridge.itf[i]);
89 90 91 92 93
            }
            VIR_FREE(def->data.bridge.itf);
            break;
        case VIR_INTERFACE_TYPE_BOND:
            VIR_FREE(def->data.bond.target);
94
            for (i = 0; i < def->data.bond.nbItf; i++) {
95
                if (def->data.bond.itf[i] == NULL)
96
                    break; /* to cope with half parsed data on errors */
97
                virInterfaceDefFree(def->data.bond.itf[i]);
98 99 100 101 102 103 104 105 106
            }
            VIR_FREE(def->data.bond.itf);
            break;
        case VIR_INTERFACE_TYPE_VLAN:
            VIR_FREE(def->data.vlan.tag);
            VIR_FREE(def->data.vlan.devname);
            break;
    }

107 108 109 110 111
    /* free all protos */
    for (pp = 0; pp < def->nprotos; pp++) {
        virInterfaceProtocolDefFree(def->protos[pp]);
    }
    VIR_FREE(def->protos);
112 113 114 115
    VIR_FREE(def);
}

static int
116
virInterfaceDefParseName(virInterfaceDefPtr def,
117 118
                         xmlXPathContextPtr ctxt)
{
119 120
    char *tmp;

121
    tmp = virXPathString("string(./@name)", ctxt);
122
    if (tmp == NULL) {
123 124
        virReportError(VIR_ERR_XML_ERROR,
                       "%s",  _("interface has no name"));
125
        return -1;
126 127
    }
    def->name = tmp;
128
    return 0;
129 130 131
}

static int
132
virInterfaceDefParseMtu(virInterfaceDefPtr def,
133 134
                        xmlXPathContextPtr ctxt)
{
135 136
    unsigned long mtu;
    int ret;
137

138
    ret = virXPathULong("string(./mtu/@size)", ctxt, &mtu);
139
    if ((ret == -2) || ((ret == 0) && (mtu > 100000))) {
140 141
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("interface mtu value is improper"));
142
        return -1;
143 144 145
    } else if (ret == 0) {
        def->mtu = (unsigned int) mtu;
    }
146
    return 0;
147 148 149
}

static int
150
virInterfaceDefParseStartMode(virInterfaceDefPtr def,
151 152
                              xmlXPathContextPtr ctxt)
{
153 154
    char *tmp;

155
    tmp = virXPathString("string(./start/@mode)", ctxt);
156 157 158
    if (tmp == NULL)
        def->startmode = VIR_INTERFACE_START_UNSPECIFIED;
    else if (STREQ(tmp, "onboot"))
159 160 161 162 163 164
        def->startmode = VIR_INTERFACE_START_ONBOOT;
    else if (STREQ(tmp, "hotplug"))
        def->startmode = VIR_INTERFACE_START_HOTPLUG;
    else if (STREQ(tmp, "none"))
        def->startmode = VIR_INTERFACE_START_NONE;
    else {
165 166
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown interface startmode %s"), tmp);
167
        VIR_FREE(tmp);
168
        return -1;
169 170
    }
    VIR_FREE(tmp);
171
    return 0;
172 173 174
}

static int
175 176
virInterfaceDefParseBondMode(xmlXPathContextPtr ctxt)
{
177 178 179
    char *tmp;
    int ret = 0;

180
    tmp = virXPathString("string(./@mode)", ctxt);
181
    if (tmp == NULL)
182
        return VIR_INTERFACE_BOND_NONE;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    if (STREQ(tmp, "balance-rr"))
        ret = VIR_INTERFACE_BOND_BALRR;
    else if (STREQ(tmp, "active-backup"))
        ret = VIR_INTERFACE_BOND_ABACKUP;
    else if (STREQ(tmp, "balance-xor"))
        ret = VIR_INTERFACE_BOND_BALXOR;
    else if (STREQ(tmp, "broadcast"))
        ret = VIR_INTERFACE_BOND_BCAST;
    else if (STREQ(tmp, "802.3ad"))
        ret = VIR_INTERFACE_BOND_8023AD;
    else if (STREQ(tmp, "balance-tlb"))
        ret = VIR_INTERFACE_BOND_BALTLB;
    else if (STREQ(tmp, "balance-alb"))
        ret = VIR_INTERFACE_BOND_BALALB;
    else {
198 199
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown bonding mode %s"), tmp);
200 201 202
        ret = -1;
    }
    VIR_FREE(tmp);
203
    return ret;
204 205 206
}

static int
207 208
virInterfaceDefParseBondMiiCarrier(xmlXPathContextPtr ctxt)
{
209 210 211
    char *tmp;
    int ret = 0;

212
    tmp = virXPathString("string(./miimon/@carrier)", ctxt);
213
    if (tmp == NULL)
214
        return VIR_INTERFACE_BOND_MII_NONE;
215 216 217 218 219
    if (STREQ(tmp, "ioctl"))
        ret = VIR_INTERFACE_BOND_MII_IOCTL;
    else if (STREQ(tmp, "netif"))
        ret = VIR_INTERFACE_BOND_MII_NETIF;
    else {
220 221
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown mii bonding carrier %s"), tmp);
222 223 224
        ret = -1;
    }
    VIR_FREE(tmp);
225
    return ret;
226 227 228
}

static int
229 230
virInterfaceDefParseBondArpValid(xmlXPathContextPtr ctxt)
{
231 232 233
    char *tmp;
    int ret = 0;

234
    tmp = virXPathString("string(./arpmon/@validate)", ctxt);
235
    if (tmp == NULL)
236
        return VIR_INTERFACE_BOND_ARP_NONE;
237 238 239 240 241 242 243
    if (STREQ(tmp, "active"))
        ret = VIR_INTERFACE_BOND_ARP_ACTIVE;
    else if (STREQ(tmp, "backup"))
        ret = VIR_INTERFACE_BOND_ARP_BACKUP;
    else if (STREQ(tmp, "all"))
        ret = VIR_INTERFACE_BOND_ARP_ALL;
    else {
244 245
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown arp bonding validate %s"), tmp);
246 247 248
        ret = -1;
    }
    VIR_FREE(tmp);
249
    return ret;
250 251 252
}

static int
253
virInterfaceDefParseDhcp(virInterfaceProtocolDefPtr def,
254 255
                         xmlNodePtr dhcp, xmlXPathContextPtr ctxt)
{
256
    xmlNodePtr save;
257 258 259
    char *tmp;
    int ret = 0;

260
    def->dhcp = 1;
261
    save = ctxt->node;
262 263
    ctxt->node = dhcp;
    /* Not much to do in the current version */
264
    tmp = virXPathString("string(./@peerdns)", ctxt);
265 266
    if (tmp) {
        if (STREQ(tmp, "yes"))
267
            def->peerdns = 1;
268
        else if (STREQ(tmp, "no"))
269
            def->peerdns = 0;
270
        else {
271 272
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown dhcp peerdns value %s"), tmp);
273 274 275 276
            ret = -1;
        }
        VIR_FREE(tmp);
    } else
277
        def->peerdns = -1;
278

279
    ctxt->node = save;
280
    return ret;
281 282 283
}

static int
284
virInterfaceDefParseIp(virInterfaceIpDefPtr def,
285 286
                       xmlXPathContextPtr ctxt)
{
287 288 289 290
    int ret = 0;
    char *tmp;
    long l;

291
    tmp = virXPathString("string(./@address)", ctxt);
292
    def->address = tmp;
293
    if (tmp != NULL) {
294
        ret = virXPathLong("string(./@prefix)", ctxt, &l);
295
        if (ret == 0)
296
            def->prefix = (int) l;
297
        else if (ret == -2) {
298 299
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("Invalid ip address prefix value"));
300
            return -1;
301 302 303
        }
    }

304
    return 0;
305 306 307
}

static int
308
virInterfaceDefParseProtoIPv4(virInterfaceProtocolDefPtr def,
309 310
                              xmlXPathContextPtr ctxt)
{
311 312
    xmlNodePtr dhcp;
    xmlNodePtr *ipNodes = NULL;
313 314
    int nIpNodes, ret = -1;
    size_t i;
315 316
    char *tmp;

317
    tmp = virXPathString("string(./route[1]/@gateway)", ctxt);
318
    def->gateway = tmp;
319

320
    dhcp = virXPathNode("./dhcp", ctxt);
321
    if (dhcp != NULL) {
322 323
        if (virInterfaceDefParseDhcp(def, dhcp, ctxt) < 0)
            return -1;
324
    }
325

326
    nIpNodes = virXPathNodeSet("./ip", ctxt, &ipNodes);
327 328
    if (nIpNodes < 0)
        return -1;
329 330 331
    if (ipNodes == NULL)
        return 0;

332
    if (VIR_ALLOC_N(def->ips, nIpNodes) < 0)
333 334 335
        goto error;

    def->nips = 0;
336
    for (i = 0; i < nIpNodes; i++) {
337 338

        virInterfaceIpDefPtr ip;
339

340
        if (VIR_ALLOC(ip) < 0)
341 342
            goto error;

343
        ctxt->node = ipNodes[i];
344
        if (virInterfaceDefParseIp(ip, ctxt) < 0) {
345 346 347 348 349 350 351 352 353 354
            virInterfaceIpDefFree(ip);
            goto error;
        }
        def->ips[def->nips++] = ip;
    }

    ret = 0;

error:
    VIR_FREE(ipNodes);
355
    return ret;
356 357 358
}

static int
359
virInterfaceDefParseProtoIPv6(virInterfaceProtocolDefPtr def,
360 361
                              xmlXPathContextPtr ctxt)
{
362 363
    xmlNodePtr dhcp, autoconf;
    xmlNodePtr *ipNodes = NULL;
364 365
    int nIpNodes, ret = -1;
    size_t i;
366 367
    char *tmp;

368
    tmp = virXPathString("string(./route[1]/@gateway)", ctxt);
369 370
    def->gateway = tmp;

371
    autoconf = virXPathNode("./autoconf", ctxt);
372 373 374
    if (autoconf != NULL)
        def->autoconf = 1;

375
    dhcp = virXPathNode("./dhcp", ctxt);
376
    if (dhcp != NULL) {
377 378
        if (virInterfaceDefParseDhcp(def, dhcp, ctxt) < 0)
            return -1;
379
    }
380

381
    nIpNodes = virXPathNodeSet("./ip", ctxt, &ipNodes);
382 383
    if (nIpNodes < 0)
        return -1;
384 385 386
    if (ipNodes == NULL)
        return 0;

387
    if (VIR_ALLOC_N(def->ips, nIpNodes) < 0)
388 389 390
        goto error;

    def->nips = 0;
391
    for (i = 0; i < nIpNodes; i++) {
392 393 394

        virInterfaceIpDefPtr ip;

395
        if (VIR_ALLOC(ip) < 0)
396 397
            goto error;

398
        ctxt->node = ipNodes[i];
399
        if (virInterfaceDefParseIp(ip, ctxt) < 0) {
400 401 402 403 404 405 406 407 408 409
            virInterfaceIpDefFree(ip);
            goto error;
        }
        def->ips[def->nips++] = ip;
    }

    ret = 0;

error:
    VIR_FREE(ipNodes);
410
    return ret;
411 412 413
}

static int
414
virInterfaceDefParseIfAdressing(virInterfaceDefPtr def,
415 416
                                xmlXPathContextPtr ctxt)
{
417 418 419
    xmlNodePtr save;
    xmlNodePtr *protoNodes = NULL;
    int nProtoNodes, pp, ret = -1;
420 421 422
    char *tmp;

    save = ctxt->node;
423

424
    nProtoNodes = virXPathNodeSet("./protocol", ctxt, &protoNodes);
425 426 427 428
    if (nProtoNodes < 0)
        goto error;

    if (nProtoNodes == 0) {
429 430
        /* no protocols is an acceptable outcome */
        return 0;
431
    }
432

433
    if (VIR_ALLOC_N(def->protos, nProtoNodes) < 0)
434
        goto error;
435

436 437 438 439 440
    def->nprotos = 0;
    for (pp = 0; pp < nProtoNodes; pp++) {

        virInterfaceProtocolDefPtr proto;

441
        if (VIR_ALLOC(proto) < 0)
442 443 444
            goto error;

        ctxt->node = protoNodes[pp];
445
        tmp = virXPathString("string(./@family)", ctxt);
446
        if (tmp == NULL) {
447 448
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("protocol misses the family attribute"));
449 450 451 452 453
            virInterfaceProtocolDefFree(proto);
            goto error;
        }
        proto->family = tmp;
        if (STREQ(tmp, "ipv4")) {
454
            ret = virInterfaceDefParseProtoIPv4(proto, ctxt);
455 456 457 458 459
            if (ret != 0) {
                virInterfaceProtocolDefFree(proto);
                goto error;
            }
        } else if (STREQ(tmp, "ipv6")) {
460
            ret = virInterfaceDefParseProtoIPv6(proto, ctxt);
461 462 463 464 465
            if (ret != 0) {
                virInterfaceProtocolDefFree(proto);
                goto error;
            }
        } else {
466 467
            virReportError(VIR_ERR_XML_ERROR,
                           _("unsupported protocol family '%s'"), tmp);
468 469 470 471 472 473 474 475 476 477
            virInterfaceProtocolDefFree(proto);
            goto error;
        }
        def->protos[def->nprotos++] = proto;
    }

    ret = 0;

error:
    VIR_FREE(protoNodes);
478
    ctxt->node = save;
479
    return ret;
480 481 482 483

}

static int
484
virInterfaceDefParseBridge(virInterfaceDefPtr def,
485 486
                           xmlXPathContextPtr ctxt)
{
487 488
    xmlNodePtr *interfaces = NULL;
    xmlNodePtr bridge;
489
    virInterfaceDefPtr itf;
490 491
    int nbItf;
    size_t i;
492 493 494
    int ret = 0;

    bridge = ctxt->node;
495
    nbItf = virXPathNodeSet("./interface", ctxt, &interfaces);
496
    if (nbItf < 0) {
497 498 499
        ret = -1;
        goto error;
    }
500 501
    if (nbItf > 0) {
        if (VIR_ALLOC_N(def->data.bridge.itf, nbItf) < 0) {
502 503 504
            ret = -1;
            goto error;
        }
505 506
        def->data.bridge.nbItf = nbItf;

507
        for (i = 0; i < nbItf; i++) {
508
            ctxt->node = interfaces[i];
509
            itf = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_BRIDGE);
510 511 512 513 514 515 516
            if (itf == NULL) {
                ret = -1;
                def->data.bridge.nbItf = i;
                goto error;
            }
            def->data.bridge.itf[i] = itf;
        }
517 518 519 520 521
    }

error:
    VIR_FREE(interfaces);
    ctxt->node = bridge;
522
    return ret;
523 524 525
}

static int
526
virInterfaceDefParseBondItfs(virInterfaceDefPtr def,
527 528
                             xmlXPathContextPtr ctxt)
{
529 530
    xmlNodePtr *interfaces = NULL;
    xmlNodePtr bond = ctxt->node;
531
    virInterfaceDefPtr itf;
532 533
    int nbItf;
    size_t i;
534 535
    int ret = 0;

536
    nbItf = virXPathNodeSet("./interface", ctxt, &interfaces);
537 538 539 540 541 542
    if (nbItf < 0) {
        ret = -1;
        goto error;
    }

    if (nbItf == 0) {
543 544
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("bond has no interfaces"));
545 546 547
        ret = -1;
        goto error;
    }
548

549 550 551 552 553 554
    if (VIR_ALLOC_N(def->data.bond.itf, nbItf) < 0) {
        ret = -1;
        goto error;
    }
    def->data.bond.nbItf = nbItf;

555
    for (i = 0; i < nbItf; i++) {
556
        ctxt->node = interfaces[i];
557
        itf = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_BOND);
558 559 560 561 562 563 564 565 566 567 568
        if (itf == NULL) {
            ret = -1;
            def->data.bond.nbItf = i;
            goto error;
        }
        def->data.bond.itf[i] = itf;
    }

error:
    VIR_FREE(interfaces);
    ctxt->node = bond;
569
    return ret;
570 571 572
}

static int
573
virInterfaceDefParseBond(virInterfaceDefPtr def,
574 575
                         xmlXPathContextPtr ctxt)
{
J
Jim Fehlig 已提交
576
    int res;
577

578
    def->data.bond.mode = virInterfaceDefParseBondMode(ctxt);
579
    if (def->data.bond.mode < 0)
J
Jim Fehlig 已提交
580
        return -1;
581

J
Jim Fehlig 已提交
582 583
    if (virInterfaceDefParseBondItfs(def, ctxt) != 0)
        return -1;
584

585
    if (virXPathNode("./miimon[1]", ctxt) != NULL) {
586 587
        def->data.bond.monit = VIR_INTERFACE_BOND_MONIT_MII;

J
Jim Fehlig 已提交
588 589 590
        res = virXPathInt("string(./miimon/@freq)", ctxt,
                          &def->data.bond.frequency);
        if ((res == -2) || (res == -1)) {
591 592
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface miimon freq missing or invalid"));
J
Jim Fehlig 已提交
593
            return -1;
594 595
        }

J
Jim Fehlig 已提交
596 597 598
        res = virXPathInt("string(./miimon/@downdelay)", ctxt,
                          &def->data.bond.downdelay);
        if (res == -2) {
599 600
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface miimon downdelay invalid"));
J
Jim Fehlig 已提交
601
            return -1;
602 603
        }

J
Jim Fehlig 已提交
604 605 606
        res = virXPathInt("string(./miimon/@updelay)", ctxt,
                          &def->data.bond.updelay);
        if (res == -2) {
607 608
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface miimon updelay invalid"));
J
Jim Fehlig 已提交
609
            return -1;
610 611
        }

612
        def->data.bond.carrier = virInterfaceDefParseBondMiiCarrier(ctxt);
J
Jim Fehlig 已提交
613 614
        if (def->data.bond.carrier < 0)
            return -1;
615

616
    } else if (virXPathNode("./arpmon[1]", ctxt) != NULL) {
617 618 619

        def->data.bond.monit = VIR_INTERFACE_BOND_MONIT_ARP;

J
Jim Fehlig 已提交
620 621 622
        res = virXPathInt("string(./arpmon/@interval)", ctxt,
                          &def->data.bond.interval);
        if ((res == -2) || (res == -1)) {
623 624
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface arpmon interval missing or invalid"));
J
Jim Fehlig 已提交
625
            return -1;
626 627 628
        }

        def->data.bond.target =
629
            virXPathString("string(./arpmon/@target)", ctxt);
630
        if (def->data.bond.target == NULL) {
631 632
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface arpmon target missing"));
J
Jim Fehlig 已提交
633
            return -1;
634 635
        }

636
        def->data.bond.validate = virInterfaceDefParseBondArpValid(ctxt);
J
Jim Fehlig 已提交
637 638
        if (def->data.bond.validate < 0)
            return -1;
639
    }
J
Jim Fehlig 已提交
640 641

    return 0;
642 643 644
}

static int
645
virInterfaceDefParseVlan(virInterfaceDefPtr def,
646 647
                         xmlXPathContextPtr ctxt)
{
648
    def->data.vlan.tag = virXPathString("string(./@tag)", ctxt);
649
    if (def->data.vlan.tag == NULL) {
650 651
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("vlan interface misses the tag attribute"));
652
        return -1;
653 654 655
    }

    def->data.vlan.devname =
656
         virXPathString("string(./interface/@name)", ctxt);
657
    if (def->data.vlan.devname == NULL) {
658 659
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("vlan interface misses name attribute"));
660
        return -1;
661
    }
662
    return 0;
663 664 665
}

static virInterfaceDefPtr
666 667
virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
{
668 669 670 671 672 673
    virInterfaceDefPtr def;
    int type;
    char *tmp;
    xmlNodePtr cur = ctxt->node;

    /* check @type */
674
    tmp = virXPathString("string(./@type)", ctxt);
675
    if (tmp == NULL) {
676 677
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("interface misses the type attribute"));
678
        return NULL;
679 680 681
    }
    type = virInterfaceTypeFromString(tmp);
    if (type == -1) {
682
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
683
                       _("unknown interface type %s"), tmp);
684
        VIR_FREE(tmp);
685
        return NULL;
686 687 688
    }
    VIR_FREE(tmp);

689
    if (VIR_ALLOC(def) < 0)
690
        return NULL;
691 692 693 694 695 696 697 698 699 700

    if (((parentIfType == VIR_INTERFACE_TYPE_BOND)
         && (type != VIR_INTERFACE_TYPE_ETHERNET))
        || ((parentIfType == VIR_INTERFACE_TYPE_BRIDGE)
            && (type != VIR_INTERFACE_TYPE_ETHERNET)
            && (type != VIR_INTERFACE_TYPE_BOND)
            && (type != VIR_INTERFACE_TYPE_VLAN))
        || (parentIfType == VIR_INTERFACE_TYPE_ETHERNET)
        || (parentIfType == VIR_INTERFACE_TYPE_VLAN))
        {
701 702 703
        virReportError(VIR_ERR_XML_ERROR,
                       _("interface has unsupported type '%s'"),
                       virInterfaceTypeToString(type));
704 705
        goto error;
    }
706 707 708
    def->type = type;
    switch (type) {
        case VIR_INTERFACE_TYPE_ETHERNET:
709
            if (virInterfaceDefParseName(def, ctxt) < 0)
710
                goto error;
711
            tmp = virXPathString("string(./mac/@address)", ctxt);
712 713
            if (tmp != NULL)
                def->mac = tmp;
714 715
            if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
                /* only recognize these in toplevel bond interfaces */
716
                if (virInterfaceDefParseStartMode(def, ctxt) < 0)
717
                    goto error;
718
                if (virInterfaceDefParseMtu(def, ctxt) < 0)
719
                    goto error;
720
                if (virInterfaceDefParseIfAdressing(def, ctxt) < 0)
721 722
                    goto error;
            }
723 724 725 726
            break;
        case VIR_INTERFACE_TYPE_BRIDGE: {
            xmlNodePtr bridge;

727
            if (virInterfaceDefParseName(def, ctxt) < 0)
728
                goto error;
729
            if (virInterfaceDefParseStartMode(def, ctxt) < 0)
730
                goto error;
731
            if (virInterfaceDefParseMtu(def, ctxt) < 0)
732
                goto error;
733
            if (virInterfaceDefParseIfAdressing(def, ctxt) < 0)
734 735
                goto error;

736
            bridge = virXPathNode("./bridge[1]", ctxt);
737
            if (bridge == NULL) {
738 739
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("bridge interface misses the bridge element"));
740 741 742 743 744 745 746 747 748 749
                goto error;
            }
            tmp = virXMLPropString(bridge, "stp");
            def->data.bridge.stp = -1;
            if (tmp != NULL) {
                if (STREQ(tmp, "on")) {
                    def->data.bridge.stp = 1;
                } else if (STREQ(tmp, "off")) {
                    def->data.bridge.stp = 0;
                } else {
750 751 752
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("bridge interface stp should be on or off got %s"),
                                   tmp);
753 754 755 756 757
                    VIR_FREE(tmp);
                    goto error;
                }
                VIR_FREE(tmp);
            }
758
            def->data.bridge.delay = virXMLPropString(bridge, "delay");
759
            ctxt->node = bridge;
760 761
            if (virInterfaceDefParseBridge(def, ctxt) < 0)
                goto error;
762 763 764 765 766
            break;
        }
        case VIR_INTERFACE_TYPE_BOND: {
            xmlNodePtr bond;

767
            if (virInterfaceDefParseName(def, ctxt) < 0)
768
                goto error;
769 770
            if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
                /* only recognize these in toplevel bond interfaces */
771
                if (virInterfaceDefParseStartMode(def, ctxt) < 0)
772
                    goto error;
773
                if (virInterfaceDefParseMtu(def, ctxt) < 0)
774
                    goto error;
775
                if (virInterfaceDefParseIfAdressing(def, ctxt) < 0)
776 777 778
                    goto error;
            }

779
            bond = virXPathNode("./bond[1]", ctxt);
780
            if (bond == NULL) {
781 782
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("bond interface misses the bond element"));
783 784 785
                goto error;
            }
            ctxt->node = bond;
786
            if (virInterfaceDefParseBond(def, ctxt)  < 0)
787 788 789 790 791 792
                goto error;
            break;
        }
        case VIR_INTERFACE_TYPE_VLAN: {
            xmlNodePtr vlan;

793
            tmp = virXPathString("string(./@name)", ctxt);
794 795
            if (tmp != NULL)
                def->name = tmp;
796
            if (virInterfaceDefParseStartMode(def, ctxt) < 0)
797
                goto error;
798
            if (virInterfaceDefParseIfAdressing(def, ctxt) < 0)
799
                goto error;
800
            vlan = virXPathNode("./vlan[1]", ctxt);
801
            if (vlan == NULL) {
802 803
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("vlan interface misses the vlan element"));
804 805 806
                goto error;
            }
            ctxt->node = vlan;
807
            if (virInterfaceDefParseVlan(def, ctxt)  < 0)
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
                goto error;
            break;
        }

    }

    ctxt->node = cur;
    return def;

error:
    ctxt->node = cur;
    virInterfaceDefFree(def);
    return NULL;
}

823 824
virInterfaceDefPtr virInterfaceDefParseNode(xmlDocPtr xml,
                                            xmlNodePtr root)
825 826 827 828 829
{
    xmlXPathContextPtr ctxt = NULL;
    virInterfaceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "interface")) {
830 831 832 833
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <interface>"),
                       root->name);
834 835 836 837 838
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
839
        virReportOOMError();
840 841 842 843
        goto cleanup;
    }

    ctxt->node = root;
844
    def = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_LAST);
845 846 847 848 849 850

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

J
Jiri Denemark 已提交
851 852 853
static virInterfaceDefPtr
virInterfaceDefParse(const char *xmlStr,
                     const char *filename)
854
{
J
Jiri Denemark 已提交
855
    xmlDocPtr xml;
856 857
    virInterfaceDefPtr def = NULL;

858
    if ((xml = virXMLParse(filename, xmlStr, _("(interface_definition)")))) {
J
Jiri Denemark 已提交
859 860
        def = virInterfaceDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
861 862 863 864 865
    }

    return def;
}

J
Jiri Denemark 已提交
866
virInterfaceDefPtr virInterfaceDefParseString(const char *xmlStr)
867
{
J
Jiri Denemark 已提交
868 869
    return virInterfaceDefParse(xmlStr, NULL);
}
870

J
Jiri Denemark 已提交
871 872 873
virInterfaceDefPtr virInterfaceDefParseFile(const char *filename)
{
    return virInterfaceDefParse(NULL, filename);
874 875 876
}

static int
877
virInterfaceBridgeDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
878
{
879
    size_t i;
880 881
    int ret = 0;

882
    virBufferAddLit(buf, "<bridge");
883
    if (def->data.bridge.stp == 1)
884
        virBufferAddLit(buf, " stp='on'");
885
    else if (def->data.bridge.stp == 0)
886 887
        virBufferAddLit(buf, " stp='off'");
    if (def->data.bridge.delay != NULL)
888
        virBufferAsprintf(buf, " delay='%s'", def->data.bridge.delay);
889
    virBufferAddLit(buf, ">\n");
890
    virBufferAdjustIndent(buf, 2);
891

892
    for (i = 0; i < def->data.bridge.nbItf; i++) {
893
        if (virInterfaceDefDevFormat(buf, def->data.bridge.itf[i]) < 0)
894 895 896
            ret = -1;
    }

897 898
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</bridge>\n");
899
    return ret;
900 901 902
}

static int
903
virInterfaceBondDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
904
{
905
    size_t i;
906 907
    int ret = 0;

908
    virBufferAddLit(buf, "<bond");
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
    if (def->data.bond.mode == VIR_INTERFACE_BOND_BALRR)
        virBufferAddLit(buf, " mode='balance-rr'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_ABACKUP)
        virBufferAddLit(buf, " mode='active-backup'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_BALXOR)
        virBufferAddLit(buf, " mode='balance-xor'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_BCAST)
        virBufferAddLit(buf, " mode='broadcast'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_8023AD)
        virBufferAddLit(buf, " mode='802.3ad'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_BALTLB)
        virBufferAddLit(buf, " mode='balance-tlb'");
    else if (def->data.bond.mode == VIR_INTERFACE_BOND_BALALB)
        virBufferAddLit(buf, " mode='balance-alb'");
    virBufferAddLit(buf, ">\n");
924
    virBufferAdjustIndent(buf, 2);
925 926

    if (def->data.bond.monit == VIR_INTERFACE_BOND_MONIT_MII) {
927 928
        virBufferAsprintf(buf, "<miimon freq='%d'",
                          def->data.bond.frequency);
929
        if (def->data.bond.downdelay > 0)
930
            virBufferAsprintf(buf, " downdelay='%d'", def->data.bond.downdelay);
931
        if (def->data.bond.updelay > 0)
932
            virBufferAsprintf(buf, " updelay='%d'", def->data.bond.updelay);
933 934 935 936 937 938 939
        if (def->data.bond.carrier == VIR_INTERFACE_BOND_MII_IOCTL)
            virBufferAddLit(buf, " carrier='ioctl'");
        else if (def->data.bond.carrier == VIR_INTERFACE_BOND_MII_NETIF)
            virBufferAddLit(buf, " carrier='netif'");
        virBufferAddLit(buf, "/>\n");
    } else if (def->data.bond.monit == VIR_INTERFACE_BOND_MONIT_ARP) {
        if (def->data.bond.target == NULL) {
940 941
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("bond arp monitoring has no target"));
942
            return -1;
943
        }
944
        virBufferAsprintf(buf, "<arpmon interval='%d' target='%s'",
945 946 947 948 949 950 951 952 953
                          def->data.bond.interval, def->data.bond.target);
        if (def->data.bond.validate == VIR_INTERFACE_BOND_ARP_ACTIVE)
            virBufferAddLit(buf, " validate='active'");
        else if (def->data.bond.validate == VIR_INTERFACE_BOND_ARP_BACKUP)
            virBufferAddLit(buf, " validate='backup'");
        else if (def->data.bond.validate == VIR_INTERFACE_BOND_ARP_ALL)
            virBufferAddLit(buf, " validate='all'");
        virBufferAddLit(buf, "/>\n");
    }
954
    for (i = 0; i < def->data.bond.nbItf; i++) {
955
        if (virInterfaceDefDevFormat(buf, def->data.bond.itf[i]) < 0)
956 957 958
            ret = -1;
    }

959 960
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</bond>\n");
961
    return ret;
962 963 964
}

static int
965
virInterfaceVlanDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
966
{
967
    if (def->data.vlan.tag == NULL) {
968 969
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vlan misses the tag name"));
970
        return -1;
971 972
    }

973
    virBufferAsprintf(buf, "<vlan tag='%s'", def->data.vlan.tag);
974 975
    if (def->data.vlan.devname != NULL) {
        virBufferAddLit(buf, ">\n");
976 977 978 979 980
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<interface name='%s'/>\n",
                          def->data.vlan.devname);
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</vlan>\n");
981 982
    } else
        virBufferAddLit(buf, "/>\n");
983
    return 0;
984 985 986
}

static int
987
virInterfaceProtocolDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
988
{
989
    size_t i, j;
990

991
    for (i = 0; i < def->nprotos; i++) {
992

993 994 995
        virBufferAsprintf(buf, "<protocol family='%s'>\n",
                          def->protos[i]->family);
        virBufferAdjustIndent(buf, 2);
996

997 998
        if (def->protos[i]->autoconf)
            virBufferAddLit(buf, "<autoconf/>\n");
999 1000
        if (def->protos[i]->dhcp) {
            if (def->protos[i]->peerdns == 0)
1001
                virBufferAddLit(buf, "<dhcp peerdns='no'/>\n");
1002
            else if (def->protos[i]->peerdns == 1)
1003
                virBufferAddLit(buf, "<dhcp peerdns='yes'/>\n");
1004
            else
1005
                virBufferAddLit(buf, "<dhcp/>\n");
1006 1007
        }

1008 1009
        for (j = 0; j < def->protos[i]->nips; j++) {
            if (def->protos[i]->ips[j]->address != NULL) {
1010

1011
                virBufferAsprintf(buf, "<ip address='%s'",
1012 1013
                                  def->protos[i]->ips[j]->address);
                if (def->protos[i]->ips[j]->prefix != 0) {
1014
                    virBufferAsprintf(buf, " prefix='%d'",
1015
                                      def->protos[i]->ips[j]->prefix);
1016 1017 1018 1019
                }
                virBufferAddLit(buf, "/>\n");
            }
        }
1020
        if (def->protos[i]->gateway != NULL) {
1021 1022
            virBufferAsprintf(buf, "<route gateway='%s'/>\n",
                              def->protos[i]->gateway);
1023 1024
        }

1025 1026
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</protocol>\n");
1027
    }
1028
    return 0;
1029 1030 1031
}

static int
1032
virInterfaceStartmodeDefFormat(virBufferPtr buf,
1033 1034
                               enum virInterfaceStartMode startmode)
{
1035 1036
    const char *mode;
    switch (startmode) {
1037 1038
        case VIR_INTERFACE_START_UNSPECIFIED:
            return 0;
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
        case VIR_INTERFACE_START_NONE:
            mode = "none";
            break;
        case VIR_INTERFACE_START_ONBOOT:
            mode = "onboot";
            break;
        case VIR_INTERFACE_START_HOTPLUG:
            mode = "hotplug";
            break;
        default:
1049 1050
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("virInterfaceDefFormat unknown startmode"));
1051 1052
            return -1;
    }
1053
    virBufferAsprintf(buf, "<start mode='%s'/>\n", mode);
1054
    return 0;
1055 1056
}

1057
static int
1058
virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
1059
{
1060
    const char *type = NULL;
1061

1062
    if (def == NULL) {
1063 1064
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("virInterfaceDefFormat NULL def"));
1065 1066 1067 1068
        goto cleanup;
    }

    if ((def->name == NULL) && (def->type != VIR_INTERFACE_TYPE_VLAN)) {
1069 1070
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("virInterfaceDefFormat missing interface name"));
1071 1072 1073 1074
        goto cleanup;
    }

    if (!(type = virInterfaceTypeToString(def->type))) {
1075 1076
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected interface type %d"), def->type);
1077 1078 1079
        goto cleanup;
    }

1080
    virBufferAsprintf(buf, "<interface type='%s' ", type);
1081
    if (def->name != NULL)
1082 1083
        virBufferEscapeString(buf, "name='%s'", def->name);
    virBufferAddLit(buf, ">\n");
1084
    virBufferAdjustIndent(buf, 2);
1085 1086 1087

    switch (def->type) {
        case VIR_INTERFACE_TYPE_ETHERNET:
1088
            virInterfaceStartmodeDefFormat(buf, def->startmode);
1089
            if (def->mac != NULL)
1090
                virBufferAsprintf(buf, "<mac address='%s'/>\n", def->mac);
1091
            if (def->mtu != 0)
1092 1093
                virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
            virInterfaceProtocolDefFormat(buf, def);
1094 1095
            break;
        case VIR_INTERFACE_TYPE_BRIDGE:
1096
            virInterfaceStartmodeDefFormat(buf, def->startmode);
1097
            if (def->mtu != 0)
1098 1099 1100
                virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
            virInterfaceProtocolDefFormat(buf, def);
            virInterfaceBridgeDefFormat(buf, def);
1101 1102
            break;
        case VIR_INTERFACE_TYPE_BOND:
1103
            virInterfaceStartmodeDefFormat(buf, def->startmode);
1104
            if (def->mtu != 0)
1105 1106 1107
                virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
            virInterfaceProtocolDefFormat(buf, def);
            virInterfaceBondDefFormat(buf, def);
1108 1109
            break;
        case VIR_INTERFACE_TYPE_VLAN:
1110
            virInterfaceStartmodeDefFormat(buf, def->startmode);
1111
            if (def->mac != NULL)
1112
                virBufferAsprintf(buf, "<mac address='%s'/>\n", def->mac);
1113
            if (def->mtu != 0)
1114 1115 1116
                virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
            virInterfaceProtocolDefFormat(buf, def);
            virInterfaceVlanDefFormat(buf, def);
1117 1118 1119
            break;
    }

1120 1121
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</interface>\n");
1122

1123
    if (virBufferError(buf))
1124
        goto no_memory;
1125
    return 0;
1126
no_memory:
1127
    virReportOOMError();
1128
cleanup:
1129 1130 1131
    return -1;
}

E
Eric Blake 已提交
1132
char *virInterfaceDefFormat(const virInterfaceDef *def)
1133 1134 1135
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1136
    if (virInterfaceDefDevFormat(&buf, def) < 0) {
1137 1138 1139 1140
        virBufferFreeAndReset(&buf);
        return NULL;
    }
    return virBufferContentAndReset(&buf);
1141 1142
}

1143 1144
/* virInterfaceObj manipulation */

1145 1146 1147 1148 1149 1150 1151 1152 1153
void virInterfaceObjLock(virInterfaceObjPtr obj)
{
    virMutexLock(&obj->lock);
}

void virInterfaceObjUnlock(virInterfaceObjPtr obj)
{
    virMutexUnlock(&obj->lock);
}
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166

void virInterfaceObjFree(virInterfaceObjPtr iface)
{
    if (!iface)
        return;

    virInterfaceDefFree(iface->def);
    virMutexDestroy(&iface->lock);
    VIR_FREE(iface);
}

/* virInterfaceObjList manipulation */

E
Eric Blake 已提交
1167
int virInterfaceFindByMACString(virInterfaceObjListPtr interfaces,
1168 1169 1170
                                const char *mac,
                                virInterfaceObjPtr *matches, int maxmatches)
{
1171 1172
    size_t i;
    unsigned int matchct = 0;
1173

1174
    for (i = 0; i < interfaces->count; i++) {
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191

        virInterfaceObjLock(interfaces->objs[i]);
        if (STRCASEEQ(interfaces->objs[i]->def->mac, mac)) {
            matchct++;
            if (matchct <= maxmatches) {
                matches[matchct - 1] = interfaces->objs[i];
                /* keep the lock if we're returning object to caller */
                /* it is the caller's responsibility to unlock *all* matches */
                continue;
            }
        }
        virInterfaceObjUnlock(interfaces->objs[i]);

    }
    return matchct;
}

E
Eric Blake 已提交
1192
virInterfaceObjPtr virInterfaceFindByName(virInterfaceObjListPtr interfaces,
1193 1194
                                          const char *name)
{
1195
    size_t i;
1196

1197
    for (i = 0; i < interfaces->count; i++) {
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
        virInterfaceObjLock(interfaces->objs[i]);
        if (STREQ(interfaces->objs[i]->def->name, name))
            return interfaces->objs[i];
        virInterfaceObjUnlock(interfaces->objs[i]);
    }

    return NULL;
}

void virInterfaceObjListFree(virInterfaceObjListPtr interfaces)
{
1209
    size_t i;
1210

1211
    for (i = 0; i < interfaces->count; i++)
1212 1213 1214 1215 1216 1217
        virInterfaceObjFree(interfaces->objs[i]);

    VIR_FREE(interfaces->objs);
    interfaces->count = 0;
}

1218 1219 1220 1221
int virInterfaceObjListClone(virInterfaceObjListPtr src,
                             virInterfaceObjListPtr dest)
{
    int ret = -1;
1222 1223
    size_t i;
    unsigned int cnt;
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256

    if (!src || !dest)
        goto cleanup;

    virInterfaceObjListFree(dest); /* start with an empty list */
    cnt = src->count;
    for (i = 0; i < cnt; i++) {
        virInterfaceDefPtr def = src->objs[i]->def;
        virInterfaceDefPtr backup;
        virInterfaceObjPtr iface;
        char *xml = virInterfaceDefFormat(def);

        if (!xml)
            goto cleanup;

        if ((backup = virInterfaceDefParseString(xml)) == NULL) {
            VIR_FREE(xml);
            goto cleanup;
        }

        VIR_FREE(xml);
        if ((iface = virInterfaceAssignDef(dest, backup)) == NULL)
            goto cleanup;
        virInterfaceObjUnlock(iface); /* was locked by virInterfaceAssignDef */
    }

    ret = cnt;
cleanup:
    if ((ret < 0) && dest)
       virInterfaceObjListFree(dest);
    return ret;
}

1257
virInterfaceObjPtr virInterfaceAssignDef(virInterfaceObjListPtr interfaces,
E
Eric Blake 已提交
1258
                                         virInterfaceDefPtr def)
1259
{
1260
    virInterfaceObjPtr iface;
1261

1262
    if ((iface = virInterfaceFindByName(interfaces, def->name))) {
1263
        virInterfaceDefFree(iface->def);
1264
        iface->def = def;
1265

1266
        return iface;
1267 1268
    }

1269
    if (VIR_ALLOC(iface) < 0)
1270
        return NULL;
1271
    if (virMutexInit(&iface->lock) < 0) {
1272 1273
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
1274
        VIR_FREE(iface);
1275 1276
        return NULL;
    }
1277
    virInterfaceObjLock(iface);
1278

1279 1280 1281
    if (VIR_APPEND_ELEMENT_COPY(interfaces->objs,
                                interfaces->count, iface) < 0) {
        virInterfaceObjFree(iface);
1282 1283 1284
        return NULL;
    }

1285
    iface->def = def;
1286
    return iface;
1287 1288 1289 1290

}

void virInterfaceRemove(virInterfaceObjListPtr interfaces,
E
Eric Blake 已提交
1291
                        virInterfaceObjPtr iface)
1292
{
1293
    size_t i;
1294

1295
    virInterfaceObjUnlock(iface);
1296
    for (i = 0; i < interfaces->count; i++) {
1297
        virInterfaceObjLock(interfaces->objs[i]);
1298
        if (interfaces->objs[i] == iface) {
1299 1300 1301
            virInterfaceObjUnlock(interfaces->objs[i]);
            virInterfaceObjFree(interfaces->objs[i]);

1302
            VIR_DELETE_ELEMENT(interfaces->objs, i, interfaces->count);
1303 1304 1305 1306 1307
            break;
        }
        virInterfaceObjUnlock(interfaces->objs[i]);
    }
}