virinterfaceobj.c 13.4 KB
Newer Older
J
John Ferlan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * virinterfaceobj.c: interface object handling
 *                    (derived from interface_conf.c)
 *
 * 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
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "datatypes.h"
#include "interface_conf.h"

#include "viralloc.h"
#include "virerror.h"
#include "virinterfaceobj.h"
28
#include "virhash.h"
J
John Ferlan 已提交
29 30 31 32 33 34 35
#include "virlog.h"
#include "virstring.h"

#define VIR_FROM_THIS VIR_FROM_INTERFACE

VIR_LOG_INIT("conf.virinterfaceobj");

36
struct _virInterfaceObj {
37
    virObjectLockable parent;
38 39 40 41

    bool active;           /* true if interface is active (up) */
    virInterfaceDefPtr def; /* The interface definition */
};
J
John Ferlan 已提交
42

43
struct _virInterfaceObjList {
44 45
    virObjectRWLockable parent;

46 47 48
    /* name string -> virInterfaceObj  mapping
     * for O(1), lockless lookup-by-name */
    virHashTable *objsName;
49
};
J
John Ferlan 已提交
50 51 52

/* virInterfaceObj manipulation */

53
static virClassPtr virInterfaceObjClass;
54
static virClassPtr virInterfaceObjListClass;
55
static void virInterfaceObjDispose(void *obj);
56
static void virInterfaceObjListDispose(void *obj);
57 58 59 60

static int
virInterfaceObjOnceInit(void)
{
61
    if (!VIR_CLASS_NEW(virInterfaceObj, virClassForObjectLockable()))
62 63
        return -1;

64
    if (!VIR_CLASS_NEW(virInterfaceObjList, virClassForObjectRWLockable()))
65 66
        return -1;

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    return 0;
}

VIR_ONCE_GLOBAL_INIT(virInterfaceObj)


static void
virInterfaceObjDispose(void *opaque)
{
    virInterfaceObjPtr obj = opaque;

    virInterfaceDefFree(obj->def);
}


82
static virInterfaceObjPtr
83
virInterfaceObjNew(void)
84 85 86
{
    virInterfaceObjPtr obj;

87
    if (virInterfaceObjInitialize() < 0)
88 89
        return NULL;

90
    if (!(obj = virObjectLockableNew(virInterfaceObjClass)))
91 92
        return NULL;

93
    virObjectLock(obj);
94 95 96 97 98

    return obj;
}


99
void
100
virInterfaceObjEndAPI(virInterfaceObjPtr *obj)
J
John Ferlan 已提交
101
{
102
    if (!*obj)
J
John Ferlan 已提交
103 104
        return;

105 106 107
    virObjectUnlock(*obj);
    virObjectUnref(*obj);
    *obj = NULL;
J
John Ferlan 已提交
108 109 110
}


111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
virInterfaceDefPtr
virInterfaceObjGetDef(virInterfaceObjPtr obj)
{
    return obj->def;
}


bool
virInterfaceObjIsActive(virInterfaceObjPtr obj)
{
    return obj->active;
}


void
virInterfaceObjSetActive(virInterfaceObjPtr obj,
                         bool active)
{
    obj->active = active;
}


133
/* virInterfaceObjList manipulation */
134 135 136 137 138
virInterfaceObjListPtr
virInterfaceObjListNew(void)
{
    virInterfaceObjListPtr interfaces;

139 140 141 142
    if (virInterfaceObjInitialize() < 0)
        return NULL;

    if (!(interfaces = virObjectRWLockableNew(virInterfaceObjListClass)))
143
        return NULL;
144

145 146 147 148 149
    if (!(interfaces->objsName = virHashCreate(10, virObjectFreeHashData))) {
        virObjectUnref(interfaces);
        return NULL;
    }

150 151 152 153
    return interfaces;
}


154 155 156
struct _virInterfaceObjFindMACData {
    const char *matchStr;
    bool error;
157 158 159
    int nnames;
    int maxnames;
    char **const names;
160 161 162 163 164 165 166 167 168 169 170 171 172
};

static int
virInterfaceObjListFindByMACStringCb(void *payload,
                                     const void *name ATTRIBUTE_UNUSED,
                                     void *opaque)
{
    virInterfaceObjPtr obj = payload;
    struct _virInterfaceObjFindMACData *data = opaque;

    if (data->error)
        return 0;

173
    if (data->nnames == data->maxnames)
174 175 176 177 178
        return 0;

    virObjectLock(obj);

    if (STRCASEEQ(obj->def->mac, data->matchStr)) {
179
        if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) {
180 181 182
            data->error = true;
            goto cleanup;
        }
183
        data->nnames++;
184 185 186 187 188 189 190 191
    }

 cleanup:
    virObjectUnlock(obj);
    return 0;
}


192
int
193 194
virInterfaceObjListFindByMACString(virInterfaceObjListPtr interfaces,
                                   const char *mac,
195
                                   char **const matches,
196
                                   int maxmatches)
J
John Ferlan 已提交
197
{
198 199
    struct _virInterfaceObjFindMACData data = { .matchStr = mac,
                                                .error = false,
200 201 202
                                                .nnames = 0,
                                                .maxnames = maxmatches,
                                                .names = matches };
J
John Ferlan 已提交
203

204
    virObjectRWLockRead(interfaces);
205 206
    virHashForEach(interfaces->objsName, virInterfaceObjListFindByMACStringCb,
                   &data);
207
    virObjectRWUnlock(interfaces);
208 209 210 211

    if (data.error)
        goto error;

212
    return data.nnames;
213 214

 error:
215 216
    while (--data.nnames >= 0)
        VIR_FREE(data.names[data.nnames]);
217 218

    return -1;
J
John Ferlan 已提交
219 220
}

221

222 223 224 225 226 227 228 229
static virInterfaceObjPtr
virInterfaceObjListFindByNameLocked(virInterfaceObjListPtr interfaces,
                                    const char *name)
{
    return virObjectRef(virHashLookup(interfaces->objsName, name));
}


230
virInterfaceObjPtr
231 232
virInterfaceObjListFindByName(virInterfaceObjListPtr interfaces,
                              const char *name)
J
John Ferlan 已提交
233
{
234
    virInterfaceObjPtr obj;
235
    virObjectRWLockRead(interfaces);
236
    obj = virInterfaceObjListFindByNameLocked(interfaces, name);
237
    virObjectRWUnlock(interfaces);
238 239
    if (obj)
        virObjectLock(obj);
J
John Ferlan 已提交
240

241
    return obj;
J
John Ferlan 已提交
242 243
}

244

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
#define MATCH(FLAG) (flags & (FLAG))
static bool
virInterfaceObjMatch(virInterfaceObjPtr obj,
                     unsigned int flags)
{
    /* filter by active state */
    if (MATCH(VIR_CONNECT_LIST_INTERFACES_FILTERS_ACTIVE) &&
        !((MATCH(VIR_CONNECT_LIST_INTERFACES_ACTIVE) &&
           virInterfaceObjIsActive(obj)) ||
          (MATCH(VIR_CONNECT_LIST_INTERFACES_INACTIVE) &&
           !virInterfaceObjIsActive(obj))))
        return false;

    return true;
}
#undef MATCH


263 264 265
typedef struct _virInterfaceObjListExportData virInterfaceObjListExportData;
typedef virInterfaceObjListExportData *virInterfaceObjListExportDataPtr;
struct _virInterfaceObjListExportData {
266 267 268 269 270 271 272 273 274
    virConnectPtr conn;
    virInterfacePtr *ifaces;
    virInterfaceObjListFilter filter;
    unsigned int flags;
    int nifaces;
    bool error;
};

static int
275 276 277
virInterfaceObjListExportCallback(void *payload,
                                  const void *name ATTRIBUTE_UNUSED,
                                  void *opaque)
278
{
279
    virInterfaceObjListExportDataPtr data = opaque;
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    virInterfaceObjPtr obj = payload;
    virInterfacePtr iface = NULL;

    if (data->error)
        return 0;

    virObjectLock(obj);

    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;

    if (!virInterfaceObjMatch(obj, data->flags))
        goto cleanup;

    if (!data->ifaces) {
        data->nifaces++;
        goto cleanup;
    }

    if (!(iface = virGetInterface(data->conn, obj->def->name, obj->def->mac))) {
        data->error = true;
        goto cleanup;
    }

    data->ifaces[data->nifaces++] = iface;

 cleanup:
    virObjectUnlock(obj);
    return 0;
}


int
virInterfaceObjListExport(virConnectPtr conn,
                          virInterfaceObjListPtr ifaceobjs,
                          virInterfacePtr **ifaces,
                          virInterfaceObjListFilter filter,
                          unsigned int flags)
{
    int ret = -1;
321
    virInterfaceObjListExportData data = {
322 323 324 325 326 327 328 329
        .conn = conn, .ifaces = NULL, .filter = filter, .flags = flags,
        .nifaces = 0, .error = false };

    virObjectRWLockRead(ifaceobjs);
    if (ifaces && VIR_ALLOC_N(data.ifaces,
                              virHashSize(ifaceobjs->objsName) + 1) < 0)
        goto cleanup;

330
    virHashForEach(ifaceobjs->objsName, virInterfaceObjListExportCallback, &data);
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

    if (data.error)
        goto cleanup;

    if (data.ifaces) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(data.ifaces, data.nifaces + 1));
        *ifaces = data.ifaces;
        data.ifaces = NULL;
    }

    ret = data.nifaces;
 cleanup:
    virObjectRWUnlock(ifaceobjs);
    while (data.ifaces && data.nifaces)
        virObjectUnref(data.ifaces[--data.nifaces]);

    VIR_FREE(data.ifaces);
    return ret;
}


353
void
354
virInterfaceObjListDispose(void *obj)
J
John Ferlan 已提交
355
{
356
    virInterfaceObjListPtr interfaces = obj;
J
John Ferlan 已提交
357

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    virHashFree(interfaces->objsName);
}


struct _virInterfaceObjListCloneData {
    bool error;
    virInterfaceObjListPtr dest;
};

static int
virInterfaceObjListCloneCb(void *payload,
                           const void *name ATTRIBUTE_UNUSED,
                           void *opaque)
{
    virInterfaceObjPtr srcObj = payload;
    struct _virInterfaceObjListCloneData *data = opaque;
    char *xml = NULL;
    virInterfaceDefPtr backup = NULL;
    virInterfaceObjPtr obj;

    if (data->error)
        return 0;

    virObjectLock(srcObj);

    if (!(xml = virInterfaceDefFormat(srcObj->def)))
        goto error;

    if (!(backup = virInterfaceDefParseString(xml)))
        goto error;
    VIR_FREE(xml);

    if (!(obj = virInterfaceObjListAssignDef(data->dest, backup)))
        goto error;
    virInterfaceObjEndAPI(&obj);

    virObjectUnlock(srcObj);
    return 0;

 error:
    data->error = true;
    VIR_FREE(xml);
    virInterfaceDefFree(backup);
    virObjectUnlock(srcObj);
    return 0;
J
John Ferlan 已提交
403 404
}

405

406 407
virInterfaceObjListPtr
virInterfaceObjListClone(virInterfaceObjListPtr interfaces)
J
John Ferlan 已提交
408
{
409 410
    struct _virInterfaceObjListCloneData data = { .error = false,
                                                  .dest = NULL };
J
John Ferlan 已提交
411

412 413
    if (!interfaces)
        return NULL;
J
John Ferlan 已提交
414

415
    if (!(data.dest = virInterfaceObjListNew()))
416 417
        return NULL;

418
    virObjectRWLockRead(interfaces);
419
    virHashForEach(interfaces->objsName, virInterfaceObjListCloneCb, &data);
420
    virObjectRWUnlock(interfaces);
J
John Ferlan 已提交
421

422 423 424 425
    if (data.error)
        goto error;

    return data.dest;
426 427

 error:
428
    virObjectUnref(data.dest);
429
    return NULL;
J
John Ferlan 已提交
430 431
}

432 433

virInterfaceObjPtr
434 435
virInterfaceObjListAssignDef(virInterfaceObjListPtr interfaces,
                             virInterfaceDefPtr def)
J
John Ferlan 已提交
436
{
437
    virInterfaceObjPtr obj;
J
John Ferlan 已提交
438

439 440
    virObjectRWLockWrite(interfaces);
    if ((obj = virInterfaceObjListFindByNameLocked(interfaces, def->name))) {
441
        virInterfaceDefFree(obj->def);
442 443 444
    } else {
        if (!(obj = virInterfaceObjNew()))
            goto error;
J
John Ferlan 已提交
445

446 447 448
        if (virHashAddEntry(interfaces->objsName, def->name, obj) < 0)
            goto error;
        virObjectRef(obj);
J
John Ferlan 已提交
449 450
    }

451
    obj->def = def;
452
    virObjectRWUnlock(interfaces);
453 454 455 456 457 458 459

    return obj;

 error:
    virInterfaceObjEndAPI(&obj);
    virObjectRWUnlock(interfaces);
    return NULL;
J
John Ferlan 已提交
460 461
}

462 463

void
464 465
virInterfaceObjListRemove(virInterfaceObjListPtr interfaces,
                          virInterfaceObjPtr obj)
J
John Ferlan 已提交
466
{
467 468
    if (!obj)
        return;
J
John Ferlan 已提交
469

470
    virObjectRef(obj);
471
    virObjectUnlock(obj);
472
    virObjectRWLockWrite(interfaces);
473 474 475 476
    virObjectLock(obj);
    virHashRemoveEntry(interfaces->objsName, obj->def->name);
    virObjectUnlock(obj);
    virObjectUnref(obj);
477
    virObjectRWUnlock(interfaces);
J
John Ferlan 已提交
478
}
479 480


481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
struct _virInterfaceObjNumOfInterfacesData {
    bool wantActive;
    int count;
};

static int
virInterfaceObjListNumOfInterfacesCb(void *payload,
                                     const void *name ATTRIBUTE_UNUSED,
                                     void *opaque)
{
    virInterfaceObjPtr obj = payload;
    struct _virInterfaceObjNumOfInterfacesData *data = opaque;

    virObjectLock(obj);

    if (data->wantActive == virInterfaceObjIsActive(obj))
        data->count++;

    virObjectUnlock(obj);
    return 0;
}


504
int
505 506
virInterfaceObjListNumOfInterfaces(virInterfaceObjListPtr interfaces,
                                   bool wantActive)
507
{
508 509
    struct _virInterfaceObjNumOfInterfacesData data = {
        .wantActive = wantActive, .count = 0 };
510

511
    virObjectRWLockRead(interfaces);
512 513
    virHashForEach(interfaces->objsName, virInterfaceObjListNumOfInterfacesCb,
                   &data);
514
    virObjectRWUnlock(interfaces);
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    return data.count;
}


struct _virInterfaceObjGetNamesData {
    bool wantActive;
    bool error;
    int nnames;
    int maxnames;
    char **const names;
};

static int
virInterfaceObjListGetNamesCb(void *payload,
                              const void *name ATTRIBUTE_UNUSED,
                              void *opaque)
{
    virInterfaceObjPtr obj = payload;
    struct _virInterfaceObjGetNamesData *data = opaque;

    if (data->error)
        return 0;

    if (data->maxnames >= 0 && data->nnames == data->maxnames)
        return 0;

    virObjectLock(obj);

    if (data->wantActive != virInterfaceObjIsActive(obj))
        goto cleanup;

    if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) {
        data->error = true;
        goto cleanup;
    }

    data->nnames++;

 cleanup:
    virObjectUnlock(obj);
    return 0;
557
}
558 559 560


int
561 562 563 564
virInterfaceObjListGetNames(virInterfaceObjListPtr interfaces,
                            bool wantActive,
                            char **const names,
                            int maxnames)
565
{
566 567 568
    struct _virInterfaceObjGetNamesData data = {
        .wantActive = wantActive, .error = false, .nnames = 0,
        .maxnames = maxnames,  .names = names };
569

570
    virObjectRWLockRead(interfaces);
571
    virHashForEach(interfaces->objsName, virInterfaceObjListGetNamesCb, &data);
572
    virObjectRWUnlock(interfaces);
573

574 575
    if (data.error)
        goto error;
576

577 578 579 580 581
    return data.nnames;

 error:
    while (--data.nnames >= 0)
        VIR_FREE(data.names[data.nnames]);
582 583 584

    return -1;
}