interface_conf.c 36.1 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 45
virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def,
                         virInterfaceType parentIfType);
46

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

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

    if (def == NULL)
        return;
63
    for (i = 0; i < def->nips; i++)
64
        virInterfaceIpDefFree(def->ips[i]);
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
            }
            VIR_FREE(def->data.bond.itf);
            break;
        case VIR_INTERFACE_TYPE_VLAN:
            VIR_FREE(def->data.vlan.tag);
103
            VIR_FREE(def->data.vlan.dev_name);
104 105 106
            break;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

259
    def->dhcp = 1;
260
    save = ctxt->node;
261 262
    ctxt->node = dhcp;
    /* Not much to do in the current version */
263
    tmp = virXPathString("string(./@peerdns)", ctxt);
264
    if (tmp) {
265
        if (STREQ(tmp, "yes")) {
266
            def->peerdns = 1;
267
        } else if (STREQ(tmp, "no")) {
268
            def->peerdns = 0;
269
        } else {
270 271
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown dhcp peerdns value %s"), tmp);
272 273 274
            ret = -1;
        }
        VIR_FREE(tmp);
275
    } else {
276
        def->peerdns = -1;
277
    }
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
            virInterfaceIpDefFree(ip);
            goto error;
        }
        def->ips[def->nips++] = ip;
    }

    ret = 0;

353
 error:
354
    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
            virInterfaceIpDefFree(ip);
            goto error;
        }
        def->ips[def->nips++] = ip;
    }

    ret = 0;

408
 error:
409
    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
            virInterfaceProtocolDefFree(proto);
            goto error;
        }
        def->protos[def->nprotos++] = proto;
    }

    ret = 0;

476
 error:
477
    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
    char *tmp = NULL;
491 492
    int nbItf;
    size_t i;
493 494 495
    int ret = 0;

    bridge = ctxt->node;
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    def->data.bridge.stp = -1;
    if ((tmp = virXMLPropString(bridge, "stp"))) {
        if (STREQ(tmp, "on")) {
            def->data.bridge.stp = 1;
        } else if (STREQ(tmp, "off")) {
            def->data.bridge.stp = 0;
        } else {
            virReportError(VIR_ERR_XML_ERROR,
                           _("bridge interface stp should be on or off got %s"),
                           tmp);
            goto error;
        }
    }
    def->data.bridge.delay = virXMLPropString(bridge, "delay");

511
    nbItf = virXPathNodeSet("./interface", ctxt, &interfaces);
512
    if (nbItf < 0) {
513 514 515
        ret = -1;
        goto error;
    }
516 517
    if (nbItf > 0) {
        if (VIR_ALLOC_N(def->data.bridge.itf, nbItf) < 0) {
518 519 520
            ret = -1;
            goto error;
        }
521 522
        def->data.bridge.nbItf = nbItf;

523
        for (i = 0; i < nbItf; i++) {
524
            ctxt->node = interfaces[i];
525
            itf = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_BRIDGE);
526 527 528 529 530 531 532
            if (itf == NULL) {
                ret = -1;
                def->data.bridge.nbItf = i;
                goto error;
            }
            def->data.bridge.itf[i] = itf;
        }
533 534
    }

535
 error:
536
    VIR_FREE(tmp);
537 538
    VIR_FREE(interfaces);
    ctxt->node = bridge;
539
    return ret;
540 541 542
}

static int
543
virInterfaceDefParseBondItfs(virInterfaceDefPtr def,
544 545
                             xmlXPathContextPtr ctxt)
{
546 547
    xmlNodePtr *interfaces = NULL;
    xmlNodePtr bond = ctxt->node;
548
    virInterfaceDefPtr itf;
549 550
    int nbItf;
    size_t i;
551 552
    int ret = 0;

553
    nbItf = virXPathNodeSet("./interface", ctxt, &interfaces);
554 555 556 557 558 559
    if (nbItf < 0) {
        ret = -1;
        goto error;
    }

    if (nbItf == 0) {
560 561
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("bond has no interfaces"));
562 563 564
        ret = -1;
        goto error;
    }
565

566 567 568 569 570 571
    if (VIR_ALLOC_N(def->data.bond.itf, nbItf) < 0) {
        ret = -1;
        goto error;
    }
    def->data.bond.nbItf = nbItf;

572
    for (i = 0; i < nbItf; i++) {
573
        ctxt->node = interfaces[i];
574
        itf = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_BOND);
575 576 577 578 579 580 581 582
        if (itf == NULL) {
            ret = -1;
            def->data.bond.nbItf = i;
            goto error;
        }
        def->data.bond.itf[i] = itf;
    }

583
 error:
584 585
    VIR_FREE(interfaces);
    ctxt->node = bond;
586
    return ret;
587 588 589
}

static int
590
virInterfaceDefParseBond(virInterfaceDefPtr def,
591 592
                         xmlXPathContextPtr ctxt)
{
J
Jim Fehlig 已提交
593
    int res;
594

595
    def->data.bond.mode = virInterfaceDefParseBondMode(ctxt);
596
    if (def->data.bond.mode < 0)
J
Jim Fehlig 已提交
597
        return -1;
598

J
Jim Fehlig 已提交
599 600
    if (virInterfaceDefParseBondItfs(def, ctxt) != 0)
        return -1;
601

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

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

J
Jim Fehlig 已提交
613 614 615
        res = virXPathInt("string(./miimon/@downdelay)", ctxt,
                          &def->data.bond.downdelay);
        if (res == -2) {
616 617
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface miimon downdelay invalid"));
J
Jim Fehlig 已提交
618
            return -1;
619 620
        }

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

629
        def->data.bond.carrier = virInterfaceDefParseBondMiiCarrier(ctxt);
J
Jim Fehlig 已提交
630 631
        if (def->data.bond.carrier < 0)
            return -1;
632

633
    } else if (virXPathNode("./arpmon[1]", ctxt) != NULL) {
634 635 636

        def->data.bond.monit = VIR_INTERFACE_BOND_MONIT_ARP;

J
Jim Fehlig 已提交
637 638 639
        res = virXPathInt("string(./arpmon/@interval)", ctxt,
                          &def->data.bond.interval);
        if ((res == -2) || (res == -1)) {
640 641
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface arpmon interval missing or invalid"));
J
Jim Fehlig 已提交
642
            return -1;
643 644 645
        }

        def->data.bond.target =
646
            virXPathString("string(./arpmon/@target)", ctxt);
647
        if (def->data.bond.target == NULL) {
648 649
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("bond interface arpmon target missing"));
J
Jim Fehlig 已提交
650
            return -1;
651 652
        }

653
        def->data.bond.validate = virInterfaceDefParseBondArpValid(ctxt);
J
Jim Fehlig 已提交
654 655
        if (def->data.bond.validate < 0)
            return -1;
656
    }
J
Jim Fehlig 已提交
657 658

    return 0;
659 660 661
}

static int
662
virInterfaceDefParseVlan(virInterfaceDefPtr def,
663 664
                         xmlXPathContextPtr ctxt)
{
665
    def->data.vlan.tag = virXPathString("string(./@tag)", ctxt);
666
    if (def->data.vlan.tag == NULL) {
667 668
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("vlan interface misses the tag attribute"));
669
        return -1;
670 671
    }

672
    def->data.vlan.dev_name =
673
         virXPathString("string(./interface/@name)", ctxt);
674
    if (def->data.vlan.dev_name == NULL) {
675 676
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("vlan interface misses name attribute"));
677
        return -1;
678
    }
679
    return 0;
680 681 682
}

static virInterfaceDefPtr
683 684
virInterfaceDefParseXML(xmlXPathContextPtr ctxt, int parentIfType)
{
685 686 687 688
    virInterfaceDefPtr def;
    int type;
    char *tmp;
    xmlNodePtr cur = ctxt->node;
689 690
    xmlNodePtr lnk;

691 692

    /* check @type */
693
    tmp = virXPathString("string(./@type)", ctxt);
694
    if (tmp == NULL) {
695 696
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("interface misses the type attribute"));
697
        return NULL;
698 699 700
    }
    type = virInterfaceTypeFromString(tmp);
    if (type == -1) {
701
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
702
                       _("unknown interface type %s"), tmp);
703
        VIR_FREE(tmp);
704
        return NULL;
705 706 707
    }
    VIR_FREE(tmp);

708
    if (VIR_ALLOC(def) < 0)
709
        return NULL;
710 711 712 713 714 715 716 717 718 719

    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))
        {
720 721 722
        virReportError(VIR_ERR_XML_ERROR,
                       _("interface has unsupported type '%s'"),
                       virInterfaceTypeToString(type));
723 724
        goto error;
    }
725
    def->type = type;
726

727 728 729 730 731 732 733 734 735 736 737 738 739
    if (virInterfaceDefParseName(def, ctxt) < 0)
       goto error;

    if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
        /* only recognize these in toplevel bond interfaces */
        if (virInterfaceDefParseStartMode(def, ctxt) < 0)
            goto error;
        if (virInterfaceDefParseMtu(def, ctxt) < 0)
            goto error;
        if (virInterfaceDefParseIfAdressing(def, ctxt) < 0)
            goto error;
    }

740 741 742 743 744 745 746
    if (type != VIR_INTERFACE_TYPE_BRIDGE) {
        /* link status makes no sense for a bridge */
        lnk = virXPathNode("./link", ctxt);
        if (lnk && virInterfaceLinkParseXML(lnk, &def->lnk) < 0)
            goto error;
    }

747
    switch (type) {
748 749
        case VIR_INTERFACE_TYPE_ETHERNET:
            if ((tmp = virXPathString("string(./mac/@address)", ctxt)))
750 751 752 753 754
                def->mac = tmp;
            break;
        case VIR_INTERFACE_TYPE_BRIDGE: {
            xmlNodePtr bridge;

755
            if (!(bridge = virXPathNode("./bridge[1]", ctxt))) {
756 757
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("bridge interface misses the bridge element"));
758 759 760
                goto error;
            }
            ctxt->node = bridge;
761 762
            if (virInterfaceDefParseBridge(def, ctxt) < 0)
                goto error;
763 764 765 766 767
            break;
        }
        case VIR_INTERFACE_TYPE_BOND: {
            xmlNodePtr bond;

768
            if (!(bond = virXPathNode("./bond[1]", ctxt))) {
769 770
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("bond interface misses the bond element"));
771 772 773
                goto error;
            }
            ctxt->node = bond;
774
            if (virInterfaceDefParseBond(def, ctxt)  < 0)
775 776 777 778 779 780
                goto error;
            break;
        }
        case VIR_INTERFACE_TYPE_VLAN: {
            xmlNodePtr vlan;

781
            if (!(vlan = virXPathNode("./vlan[1]", ctxt))) {
782 783
                virReportError(VIR_ERR_XML_ERROR,
                               "%s", _("vlan interface misses the vlan element"));
784 785 786
                goto error;
            }
            ctxt->node = vlan;
787
            if (virInterfaceDefParseVlan(def, ctxt)  < 0)
788 789 790 791 792 793 794 795 796
                goto error;
            break;
        }

    }

    ctxt->node = cur;
    return def;

797
 error:
798 799 800 801 802
    ctxt->node = cur;
    virInterfaceDefFree(def);
    return NULL;
}

803 804
virInterfaceDefPtr virInterfaceDefParseNode(xmlDocPtr xml,
                                            xmlNodePtr root)
805 806 807 808 809
{
    xmlXPathContextPtr ctxt = NULL;
    virInterfaceDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "interface")) {
810 811 812 813
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <interface>"),
                       root->name);
814 815 816 817 818
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
819
        virReportOOMError();
820 821 822 823
        goto cleanup;
    }

    ctxt->node = root;
824
    def = virInterfaceDefParseXML(ctxt, VIR_INTERFACE_TYPE_LAST);
825

826
 cleanup:
827 828 829 830
    xmlXPathFreeContext(ctxt);
    return def;
}

J
Jiri Denemark 已提交
831 832 833
static virInterfaceDefPtr
virInterfaceDefParse(const char *xmlStr,
                     const char *filename)
834
{
J
Jiri Denemark 已提交
835
    xmlDocPtr xml;
836 837
    virInterfaceDefPtr def = NULL;

838
    if ((xml = virXMLParse(filename, xmlStr, _("(interface_definition)")))) {
J
Jiri Denemark 已提交
839 840
        def = virInterfaceDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
841 842 843 844 845
    }

    return def;
}

J
Jiri Denemark 已提交
846
virInterfaceDefPtr virInterfaceDefParseString(const char *xmlStr)
847
{
J
Jiri Denemark 已提交
848 849
    return virInterfaceDefParse(xmlStr, NULL);
}
850

J
Jiri Denemark 已提交
851 852 853
virInterfaceDefPtr virInterfaceDefParseFile(const char *filename)
{
    return virInterfaceDefParse(NULL, filename);
854 855 856
}

static int
857
virInterfaceBridgeDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
858
{
859
    size_t i;
860 861
    int ret = 0;

862
    virBufferAddLit(buf, "<bridge");
863
    if (def->data.bridge.stp == 1)
864
        virBufferAddLit(buf, " stp='on'");
865
    else if (def->data.bridge.stp == 0)
866 867
        virBufferAddLit(buf, " stp='off'");
    if (def->data.bridge.delay != NULL)
868
        virBufferAsprintf(buf, " delay='%s'", def->data.bridge.delay);
869
    virBufferAddLit(buf, ">\n");
870
    virBufferAdjustIndent(buf, 2);
871

872
    for (i = 0; i < def->data.bridge.nbItf; i++) {
873 874
        if (virInterfaceDefDevFormat(buf, def->data.bridge.itf[i],
                                     VIR_INTERFACE_TYPE_BRIDGE) < 0)
875 876 877
            ret = -1;
    }

878 879
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</bridge>\n");
880
    return ret;
881 882 883
}

static int
884
virInterfaceBondDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
885
{
886
    size_t i;
887 888
    int ret = 0;

889
    virBufferAddLit(buf, "<bond");
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
    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");
905
    virBufferAdjustIndent(buf, 2);
906 907

    if (def->data.bond.monit == VIR_INTERFACE_BOND_MONIT_MII) {
908 909
        virBufferAsprintf(buf, "<miimon freq='%d'",
                          def->data.bond.frequency);
910
        if (def->data.bond.downdelay > 0)
911
            virBufferAsprintf(buf, " downdelay='%d'", def->data.bond.downdelay);
912
        if (def->data.bond.updelay > 0)
913
            virBufferAsprintf(buf, " updelay='%d'", def->data.bond.updelay);
914 915 916 917 918 919 920
        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) {
921 922
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("bond arp monitoring has no target"));
923
            return -1;
924
        }
925
        virBufferAsprintf(buf, "<arpmon interval='%d' target='%s'",
926 927 928 929 930 931 932 933 934
                          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");
    }
935
    for (i = 0; i < def->data.bond.nbItf; i++) {
936 937
        if (virInterfaceDefDevFormat(buf, def->data.bond.itf[i],
                                     VIR_INTERFACE_TYPE_BOND) < 0)
938 939 940
            ret = -1;
    }

941 942
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</bond>\n");
943
    return ret;
944 945 946
}

static int
947
virInterfaceVlanDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
948
{
949
    if (def->data.vlan.tag == NULL) {
950 951
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vlan misses the tag name"));
952
        return -1;
953 954
    }

955
    virBufferAsprintf(buf, "<vlan tag='%s'", def->data.vlan.tag);
956
    if (def->data.vlan.dev_name != NULL) {
957
        virBufferAddLit(buf, ">\n");
958 959
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<interface name='%s'/>\n",
960
                          def->data.vlan.dev_name);
961 962
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</vlan>\n");
963
    } else {
964
        virBufferAddLit(buf, "/>\n");
965
    }
966
    return 0;
967 968 969
}

static int
970
virInterfaceProtocolDefFormat(virBufferPtr buf, const virInterfaceDef *def)
E
Eric Blake 已提交
971
{
972
    size_t i, j;
973

974
    for (i = 0; i < def->nprotos; i++) {
975

976 977 978
        virBufferAsprintf(buf, "<protocol family='%s'>\n",
                          def->protos[i]->family);
        virBufferAdjustIndent(buf, 2);
979

980 981
        if (def->protos[i]->autoconf)
            virBufferAddLit(buf, "<autoconf/>\n");
982 983
        if (def->protos[i]->dhcp) {
            if (def->protos[i]->peerdns == 0)
984
                virBufferAddLit(buf, "<dhcp peerdns='no'/>\n");
985
            else if (def->protos[i]->peerdns == 1)
986
                virBufferAddLit(buf, "<dhcp peerdns='yes'/>\n");
987
            else
988
                virBufferAddLit(buf, "<dhcp/>\n");
989 990
        }

991 992
        for (j = 0; j < def->protos[i]->nips; j++) {
            if (def->protos[i]->ips[j]->address != NULL) {
993

994
                virBufferAsprintf(buf, "<ip address='%s'",
995 996
                                  def->protos[i]->ips[j]->address);
                if (def->protos[i]->ips[j]->prefix != 0) {
997
                    virBufferAsprintf(buf, " prefix='%d'",
998
                                      def->protos[i]->ips[j]->prefix);
999 1000 1001 1002
                }
                virBufferAddLit(buf, "/>\n");
            }
        }
1003
        if (def->protos[i]->gateway != NULL) {
1004 1005
            virBufferAsprintf(buf, "<route gateway='%s'/>\n",
                              def->protos[i]->gateway);
1006 1007
        }

1008 1009
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</protocol>\n");
1010
    }
1011
    return 0;
1012 1013 1014
}

static int
1015
virInterfaceStartmodeDefFormat(virBufferPtr buf,
1016
                               virInterfaceStartMode startmode)
1017
{
1018 1019
    const char *mode;
    switch (startmode) {
1020 1021
        case VIR_INTERFACE_START_UNSPECIFIED:
            return 0;
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
        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:
1032 1033
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("virInterfaceDefFormat unknown startmode"));
1034 1035
            return -1;
    }
1036
    virBufferAsprintf(buf, "<start mode='%s'/>\n", mode);
1037
    return 0;
1038 1039
}

1040
static int
1041 1042
virInterfaceDefDevFormat(virBufferPtr buf, const virInterfaceDef *def,
                         virInterfaceType parentIfType)
E
Eric Blake 已提交
1043
{
1044
    const char *type = NULL;
1045

1046
    if (def == NULL) {
1047 1048
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("virInterfaceDefFormat NULL def"));
1049 1050 1051 1052
        goto cleanup;
    }

    if ((def->name == NULL) && (def->type != VIR_INTERFACE_TYPE_VLAN)) {
1053 1054
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("virInterfaceDefFormat missing interface name"));
1055 1056 1057 1058
        goto cleanup;
    }

    if (!(type = virInterfaceTypeToString(def->type))) {
1059 1060
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected interface type %d"), def->type);
1061 1062 1063
        goto cleanup;
    }

1064
    virBufferAsprintf(buf, "<interface type='%s' ", type);
1065
    if (def->name != NULL)
1066 1067
        virBufferEscapeString(buf, "name='%s'", def->name);
    virBufferAddLit(buf, ">\n");
1068
    virBufferAdjustIndent(buf, 2);
1069

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
    if (parentIfType == VIR_INTERFACE_TYPE_LAST) {
        /* these elements are only valid on top-level interfaces - IP
         * address info ("protocol") only makes sense for the
         * top-level, and subordinate interfaces inherit the toplevel
         * setting for mtu and start mode, which cannot be overridden.
         */
        virInterfaceStartmodeDefFormat(buf, def->startmode);
        if (def->mtu)
            virBufferAsprintf(buf, "<mtu size='%d'/>\n", def->mtu);
        virInterfaceProtocolDefFormat(buf, def);
    }

1082
    if (def->type != VIR_INTERFACE_TYPE_BRIDGE)
1083
        virInterfaceLinkFormat(buf, &def->lnk);
1084 1085
    switch (def->type) {
        case VIR_INTERFACE_TYPE_ETHERNET:
1086
            if (def->mac)
1087
                virBufferAsprintf(buf, "<mac address='%s'/>\n", def->mac);
1088 1089
            break;
        case VIR_INTERFACE_TYPE_BRIDGE:
1090
            virInterfaceBridgeDefFormat(buf, def);
1091 1092
            break;
        case VIR_INTERFACE_TYPE_BOND:
1093
            virInterfaceBondDefFormat(buf, def);
1094 1095
            break;
        case VIR_INTERFACE_TYPE_VLAN:
1096
            virInterfaceVlanDefFormat(buf, def);
1097 1098 1099
            break;
    }

1100 1101
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</interface>\n");
1102

1103 1104 1105
    if (virBufferCheckError(buf) < 0)
        goto cleanup;

1106
    return 0;
1107

1108
 cleanup:
1109 1110 1111
    return -1;
}

E
Eric Blake 已提交
1112
char *virInterfaceDefFormat(const virInterfaceDef *def)
1113 1114 1115
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1116
    if (virInterfaceDefDevFormat(&buf, def, VIR_INTERFACE_TYPE_LAST) < 0) {
1117 1118 1119 1120
        virBufferFreeAndReset(&buf);
        return NULL;
    }
    return virBufferContentAndReset(&buf);
1121 1122
}

1123 1124
/* virInterfaceObj manipulation */

1125 1126 1127 1128 1129 1130 1131 1132 1133
void virInterfaceObjLock(virInterfaceObjPtr obj)
{
    virMutexLock(&obj->lock);
}

void virInterfaceObjUnlock(virInterfaceObjPtr obj)
{
    virMutexUnlock(&obj->lock);
}
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146

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

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

/* virInterfaceObjList manipulation */

E
Eric Blake 已提交
1147
int virInterfaceFindByMACString(virInterfaceObjListPtr interfaces,
1148 1149 1150
                                const char *mac,
                                virInterfaceObjPtr *matches, int maxmatches)
{
1151 1152
    size_t i;
    unsigned int matchct = 0;
1153

1154
    for (i = 0; i < interfaces->count; i++) {
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171

        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 已提交
1172
virInterfaceObjPtr virInterfaceFindByName(virInterfaceObjListPtr interfaces,
1173 1174
                                          const char *name)
{
1175
    size_t i;
1176

1177
    for (i = 0; i < interfaces->count; i++) {
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
        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)
{
1189
    size_t i;
1190

1191
    for (i = 0; i < interfaces->count; i++)
1192 1193 1194 1195 1196 1197
        virInterfaceObjFree(interfaces->objs[i]);

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

1198 1199 1200 1201
int virInterfaceObjListClone(virInterfaceObjListPtr src,
                             virInterfaceObjListPtr dest)
{
    int ret = -1;
1202 1203
    size_t i;
    unsigned int cnt;
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230

    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;
1231
 cleanup:
1232 1233 1234 1235 1236
    if ((ret < 0) && dest)
       virInterfaceObjListFree(dest);
    return ret;
}

1237
virInterfaceObjPtr virInterfaceAssignDef(virInterfaceObjListPtr interfaces,
E
Eric Blake 已提交
1238
                                         virInterfaceDefPtr def)
1239
{
1240
    virInterfaceObjPtr iface;
1241

1242
    if ((iface = virInterfaceFindByName(interfaces, def->name))) {
1243
        virInterfaceDefFree(iface->def);
1244
        iface->def = def;
1245

1246
        return iface;
1247 1248
    }

1249
    if (VIR_ALLOC(iface) < 0)
1250
        return NULL;
1251
    if (virMutexInit(&iface->lock) < 0) {
1252 1253
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
1254
        VIR_FREE(iface);
1255 1256
        return NULL;
    }
1257
    virInterfaceObjLock(iface);
1258

1259 1260 1261
    if (VIR_APPEND_ELEMENT_COPY(interfaces->objs,
                                interfaces->count, iface) < 0) {
        virInterfaceObjFree(iface);
1262 1263 1264
        return NULL;
    }

1265
    iface->def = def;
1266
    return iface;
1267 1268 1269 1270

}

void virInterfaceRemove(virInterfaceObjListPtr interfaces,
E
Eric Blake 已提交
1271
                        virInterfaceObjPtr iface)
1272
{
1273
    size_t i;
1274

1275
    virInterfaceObjUnlock(iface);
1276
    for (i = 0; i < interfaces->count; i++) {
1277
        virInterfaceObjLock(interfaces->objs[i]);
1278
        if (interfaces->objs[i] == iface) {
1279 1280 1281
            virInterfaceObjUnlock(interfaces->objs[i]);
            virInterfaceObjFree(interfaces->objs[i]);

1282
            VIR_DELETE_ELEMENT(interfaces->objs, i, interfaces->count);
1283 1284 1285 1286 1287
            break;
        }
        virInterfaceObjUnlock(interfaces->objs[i]);
    }
}