virsh-nwfilter.c 20.4 KB
Newer Older
1
/*
E
Eric Blake 已提交
2
 * virsh-nwfilter.c: Commands to manage network filters
3
 *
4
 * Copyright (C) 2005, 2007-2016 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
18 19 20
 * <http://www.gnu.org/licenses/>.
 */

E
Eric Blake 已提交
21 22
#include <config.h>
#include "virsh-nwfilter.h"
23

E
Eric Blake 已提交
24
#include "internal.h"
25
#include "virbuffer.h"
26
#include "viralloc.h"
27
#include "virfile.h"
28
#include "virutil.h"
29
#include "vsh-table.h"
E
Eric Blake 已提交
30 31

virNWFilterPtr
32 33
virshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
                          const char **name, unsigned int flags)
34 35 36 37
{
    virNWFilterPtr nwfilter = NULL;
    const char *n = NULL;
    const char *optname = "nwfilter";
38 39 40
    virshControlPtr priv = ctl->privData;

    virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL);
E
Eric Blake 已提交
41

42
    if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
43 44 45 46 47 48 49 50 51
        return NULL;

    vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
             cmd->def->name, optname, n);

    if (name)
        *name = n;

    /* try it by UUID */
52
    if ((flags & VIRSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) {
53 54
        vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter UUID\n",
                 cmd->def->name, optname);
55
        nwfilter = virNWFilterLookupByUUIDString(priv->conn, n);
56 57
    }
    /* try it by NAME */
58
    if (!nwfilter && (flags & VIRSH_BYNAME)) {
59 60
        vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter NAME\n",
                 cmd->def->name, optname);
61
        nwfilter = virNWFilterLookupByName(priv->conn, n);
62 63 64 65 66 67 68 69 70 71 72 73
    }

    if (!nwfilter)
        vshError(ctl, _("failed to get nwfilter '%s'"), n);

    return nwfilter;
}

/*
 * "nwfilter-define" command
 */
static const vshCmdInfo info_nwfilter_define[] = {
74 75 76 77 78 79 80
    {.name = "help",
     .data = N_("define or update a network filter from an XML file")
    },
    {.name = "desc",
     .data = N_("Define a new network filter or update an existing one.")
    },
    {.name = NULL}
81 82 83
};

static const vshCmdOptDef opts_nwfilter_define[] = {
84 85
    VIRSH_COMMON_OPT_FILE(N_("file containing an XML network "
                             "filter description")),
86
    {.name = NULL}
87 88 89 90 91 92 93 94 95
};

static bool
cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
    const char *from = NULL;
    bool ret = true;
    char *buffer;
96
    virshControlPtr priv = ctl->privData;
97

98
    if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
99 100
        return false;

E
Eric Blake 已提交
101
    if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
102 103
        return false;

104
    nwfilter = virNWFilterDefineXML(priv->conn, buffer);
105 106 107
    VIR_FREE(buffer);

    if (nwfilter != NULL) {
P
Pino Toscano 已提交
108 109
        vshPrintExtra(ctl, _("Network filter %s defined from %s\n"),
                      virNWFilterGetName(nwfilter), from);
110 111 112 113 114 115 116 117 118 119 120 121
        virNWFilterFree(nwfilter);
    } else {
        vshError(ctl, _("Failed to define network filter from %s"), from);
        ret = false;
    }
    return ret;
}

/*
 * "nwfilter-undefine" command
 */
static const vshCmdInfo info_nwfilter_undefine[] = {
122 123 124 125 126 127 128
    {.name = "help",
     .data = N_("undefine a network filter")
    },
    {.name = "desc",
     .data = N_("Undefine a given network filter.")
    },
    {.name = NULL}
129 130 131
};

static const vshCmdOptDef opts_nwfilter_undefine[] = {
132 133 134
    {.name = "nwfilter",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
135 136
     .help = N_("network filter name or uuid"),
     .completer = virshNWFilterNameCompleter,
137 138
    },
    {.name = NULL}
139 140 141 142 143 144 145 146 147
};

static bool
cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
    bool ret = true;
    const char *name;

148
    if (!(nwfilter = virshCommandOptNWFilter(ctl, cmd, &name)))
149 150 151
        return false;

    if (virNWFilterUndefine(nwfilter) == 0) {
P
Pino Toscano 已提交
152
        vshPrintExtra(ctl, _("Network filter %s undefined\n"), name);
153 154 155 156 157 158 159 160 161 162 163 164 165
    } else {
        vshError(ctl, _("Failed to undefine network filter %s"), name);
        ret = false;
    }

    virNWFilterFree(nwfilter);
    return ret;
}

/*
 * "nwfilter-dumpxml" command
 */
static const vshCmdInfo info_nwfilter_dumpxml[] = {
166 167 168 169 170 171 172
    {.name = "help",
     .data = N_("network filter information in XML")
    },
    {.name = "desc",
     .data = N_("Output the network filter information as an XML dump to stdout.")
    },
    {.name = NULL}
173 174 175
};

static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
176 177 178
    {.name = "nwfilter",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
179 180
     .help = N_("network filter name or uuid"),
     .completer = virshNWFilterNameCompleter,
181 182
    },
    {.name = NULL}
183 184 185 186 187 188 189 190 191
};

static bool
cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterPtr nwfilter;
    bool ret = true;
    char *dump;

192
    if (!(nwfilter = virshCommandOptNWFilter(ctl, cmd, NULL)))
193 194 195 196 197 198 199 200 201 202 203 204 205 206
        return false;

    dump = virNWFilterGetXMLDesc(nwfilter, 0);
    if (dump != NULL) {
        vshPrint(ctl, "%s", dump);
        VIR_FREE(dump);
    } else {
        ret = false;
    }

    virNWFilterFree(nwfilter);
    return ret;
}

207
static int
208
virshNWFilterSorter(const void *a, const void *b)
209 210 211 212 213 214 215 216 217 218 219 220 221 222
{
    virNWFilterPtr *fa = (virNWFilterPtr *) a;
    virNWFilterPtr *fb = (virNWFilterPtr *) b;

    if (*fa && !*fb)
        return -1;

    if (!*fa)
        return *fb != NULL;

    return vshStrcasecmp(virNWFilterGetName(*fa),
                         virNWFilterGetName(*fb));
}

223
struct virshNWFilterList {
224 225 226
    virNWFilterPtr *filters;
    size_t nfilters;
};
227
typedef struct virshNWFilterList *virshNWFilterListPtr;
228 229

static void
230
virshNWFilterListFree(virshNWFilterListPtr list)
231
{
232
    size_t i;
233

234
    if (list && list->filters) {
235 236 237 238 239 240 241 242 243
        for (i = 0; i < list->nfilters; i++) {
            if (list->filters[i])
                virNWFilterFree(list->filters[i]);
        }
        VIR_FREE(list->filters);
    }
    VIR_FREE(list);
}

244 245 246
static virshNWFilterListPtr
virshNWFilterListCollect(vshControl *ctl,
                         unsigned int flags)
247
{
248
    virshNWFilterListPtr list = vshMalloc(ctl, sizeof(*list));
249
    size_t i;
250 251 252 253 254 255
    int ret;
    virNWFilterPtr filter;
    bool success = false;
    size_t deleted = 0;
    int nfilters = 0;
    char **names = NULL;
256
    virshControlPtr priv = ctl->privData;
257 258

    /* try the list with flags support (0.10.2 and later) */
259
    if ((ret = virConnectListAllNWFilters(priv->conn,
260 261 262 263 264 265 266 267 268 269 270 271 272
                                          &list->filters,
                                          flags)) >= 0) {
        list->nfilters = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) {
        vshResetLibvirtError();
        goto fallback;
    }

    /* there was an error during the call */
273
    vshError(ctl, "%s", _("Failed to list network filters"));
274 275 276
    goto cleanup;


277
 fallback:
278 279 280
    /* fall back to old method (0.9.13 and older) */
    vshResetLibvirtError();

281
    nfilters = virConnectNumOfNWFilters(priv->conn);
282 283 284 285 286 287 288 289 290 291
    if (nfilters < 0) {
        vshError(ctl, "%s", _("Failed to count network filters"));
        goto cleanup;
    }

    if (nfilters == 0)
        return list;

    names = vshMalloc(ctl, sizeof(char *) * nfilters);

292
    nfilters = virConnectListNWFilters(priv->conn, names, nfilters);
293 294 295 296 297 298 299 300 301
    if (nfilters < 0) {
        vshError(ctl, "%s", _("Failed to list network filters"));
        goto cleanup;
    }

    list->filters = vshMalloc(ctl, sizeof(virNWFilterPtr) * nfilters);
    list->nfilters = 0;

    /* get the network filters */
302
    for (i = 0; i < nfilters; i++) {
303
        if (!(filter = virNWFilterLookupByName(priv->conn, names[i])))
304 305 306 307 308 309 310
            continue;
        list->filters[list->nfilters++] = filter;
    }

    /* truncate network filters that weren't found */
    deleted = nfilters - list->nfilters;

311
 finished:
312 313 314
    /* sort the list */
    if (list->filters && list->nfilters)
        qsort(list->filters, list->nfilters,
315
              sizeof(*list->filters), virshNWFilterSorter);
316 317 318 319 320 321 322

    /* truncate the list for not found filter objects */
    if (deleted)
        VIR_SHRINK_N(list->filters, list->nfilters, deleted);

    success = true;

323
 cleanup:
324
    for (i = 0; nfilters != -1 && i < nfilters; i++)
325 326 327 328
        VIR_FREE(names[i]);
    VIR_FREE(names);

    if (!success) {
329
        virshNWFilterListFree(list);
330 331 332 333 334 335
        list = NULL;
    }

    return list;
}

336 337 338 339
/*
 * "nwfilter-list" command
 */
static const vshCmdInfo info_nwfilter_list[] = {
340 341 342 343 344 345 346
    {.name = "help",
     .data = N_("list network filters")
    },
    {.name = "desc",
     .data = N_("Returns list of network filters.")
    },
    {.name = NULL}
347 348 349
};

static const vshCmdOptDef opts_nwfilter_list[] = {
350
    {.name = NULL}
351 352 353
};

static bool
J
Ján Tomko 已提交
354
cmdNWFilterList(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
355
{
356
    size_t i;
357
    char uuid[VIR_UUID_STRING_BUFLEN];
358
    bool ret = false;
359
    virshNWFilterListPtr list = NULL;
360
    vshTablePtr table = NULL;
361

362
    if (!(list = virshNWFilterListCollect(ctl, 0)))
363 364
        return false;

365 366 367
    table = vshTableNew(_("UUID"), _("Name"), NULL);
    if (!table)
        goto cleanup;
368

369 370
    for (i = 0; i < list->nfilters; i++) {
        virNWFilterPtr nwfilter = list->filters[i];
371 372

        virNWFilterGetUUIDString(nwfilter, uuid);
373 374 375 376 377
        if (vshTableRowAppend(table,
                              uuid,
                              virNWFilterGetName(nwfilter),
                              NULL) < 0)
            goto cleanup;
378 379
    }

380 381 382 383 384
    vshTablePrintToStdout(table, ctl);

    ret = true;
 cleanup:
    vshTableFree(table);
385
    virshNWFilterListFree(list);
386
    return ret;
387 388 389 390 391 392
}

/*
 * "nwfilter-edit" command
 */
static const vshCmdInfo info_nwfilter_edit[] = {
393 394 395 396 397 398 399
    {.name = "help",
     .data = N_("edit XML configuration for a network filter")
    },
    {.name = "desc",
     .data = N_("Edit the XML configuration for a network filter.")
    },
    {.name = NULL}
400 401 402
};

static const vshCmdOptDef opts_nwfilter_edit[] = {
403 404 405
    {.name = "nwfilter",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
406 407
     .help = N_("network filter name or uuid"),
     .completer = virshNWFilterNameCompleter,
408 409
    },
    {.name = NULL}
410 411 412 413 414 415 416 417
};

static bool
cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd)
{
    bool ret = false;
    virNWFilterPtr nwfilter = NULL;
    virNWFilterPtr nwfilter_edited = NULL;
418
    virshControlPtr priv = ctl->privData;
419

420
    nwfilter = virshCommandOptNWFilter(ctl, cmd, NULL);
421 422 423 424
    if (nwfilter == NULL)
        goto cleanup;

#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0)
425 426 427 428 429 430 431
#define EDIT_NOT_CHANGED \
    do { \
        vshPrintExtra(ctl, _("Network filter %s XML " \
                        "configuration not changed.\n"), \
                 virNWFilterGetName(nwfilter)); \
        ret = true; \
        goto edit_cleanup; \
432
    } while (0)
433
#define EDIT_DEFINE \
434
    (nwfilter_edited = virNWFilterDefineXML(priv->conn, doc_edited))
435 436
#include "virsh-edit.c"

437 438
    vshPrintExtra(ctl, _("Network filter %s XML configuration edited.\n"),
                  virNWFilterGetName(nwfilter_edited));
439 440 441

    ret = true;

442
 cleanup:
443 444 445 446 447 448 449
    if (nwfilter)
        virNWFilterFree(nwfilter);
    if (nwfilter_edited)
        virNWFilterFree(nwfilter_edited);

    return ret;
}
450

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 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 504 505 506 507 508 509 510 511 512 513 514 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 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718

virNWFilterBindingPtr
virshCommandOptNWFilterBindingBy(vshControl *ctl,
                                 const vshCmd *cmd,
                                 const char **name,
                                 unsigned int flags)
{
    virNWFilterBindingPtr binding = NULL;
    const char *n = NULL;
    const char *optname = "binding";
    virshControlPtr priv = ctl->privData;

    virCheckFlags(0, NULL);

    if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
        return NULL;

    vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
             cmd->def->name, optname, n);

    if (name)
        *name = n;

    vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter binding port dev\n",
             cmd->def->name, optname);
    binding = virNWFilterBindingLookupByPortDev(priv->conn, n);

    if (!binding)
        vshError(ctl, _("failed to get nwfilter binding '%s'"), n);

    return binding;
}


/*
 * "nwfilter-binding-create" command
 */
static const vshCmdInfo info_nwfilter_binding_create[] = {
    {.name = "help",
     .data = N_("create a network filter binding from an XML file")
    },
    {.name = "desc",
     .data = N_("Create a new network filter binding.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_nwfilter_binding_create[] = {
    VIRSH_COMMON_OPT_FILE(N_("file containing an XML network "
                             "filter binding description")),
    {.name = NULL}
};

static bool
cmdNWFilterBindingCreate(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterBindingPtr binding;
    const char *from = NULL;
    bool ret = true;
    char *buffer;
    virshControlPtr priv = ctl->privData;

    if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
        return false;

    if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
        return false;

    binding = virNWFilterBindingCreateXML(priv->conn, buffer, 0);
    VIR_FREE(buffer);

    if (binding != NULL) {
        vshPrintExtra(ctl, _("Network filter binding on %s created from %s\n"),
                      virNWFilterBindingGetPortDev(binding), from);
        virNWFilterBindingFree(binding);
    } else {
        vshError(ctl, _("Failed to create network filter from %s"), from);
        ret = false;
    }
    return ret;
}


/*
 * "nwfilter-binding-delete" command
 */
static const vshCmdInfo info_nwfilter_binding_delete[] = {
    {.name = "help",
     .data = N_("delete a network filter binding")
    },
    {.name = "desc",
     .data = N_("Delete a given network filter binding.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_nwfilter_binding_delete[] = {
    {.name = "binding",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("network filter binding port dev"),
     .completer = virshNWFilterBindingNameCompleter,
    },
    {.name = NULL}
};

static bool
cmdNWFilterBindingDelete(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterBindingPtr binding;
    bool ret = true;
    const char *portdev;

    if (!(binding = virshCommandOptNWFilterBinding(ctl, cmd, &portdev)))
        return false;

    if (virNWFilterBindingDelete(binding) == 0) {
        vshPrintExtra(ctl, _("Network filter binding on %s deleted\n"), portdev);
    } else {
        vshError(ctl, _("Failed to delete network filter binding on %s"), portdev);
        ret = false;
    }

    virNWFilterBindingFree(binding);
    return ret;
}


/*
 * "nwfilter-binding-dumpxml" command
 */
static const vshCmdInfo info_nwfilter_binding_dumpxml[] = {
    {.name = "help",
     .data = N_("network filter information in XML")
    },
    {.name = "desc",
     .data = N_("Output the network filter information as an XML dump to stdout.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_nwfilter_binding_dumpxml[] = {
    {.name = "binding",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("network filter binding portdev"),
     .completer = virshNWFilterBindingNameCompleter,
    },
    {.name = NULL}
};

static bool
cmdNWFilterBindingDumpXML(vshControl *ctl, const vshCmd *cmd)
{
    virNWFilterBindingPtr binding;
    bool ret = true;
    char *dump;

    if (!(binding = virshCommandOptNWFilterBinding(ctl, cmd, NULL)))
        return false;

    dump = virNWFilterBindingGetXMLDesc(binding, 0);
    if (dump != NULL) {
        vshPrint(ctl, "%s", dump);
        VIR_FREE(dump);
    } else {
        ret = false;
    }

    virNWFilterBindingFree(binding);
    return ret;
}


static int
virshNWFilterBindingSorter(const void *a, const void *b)
{
    virNWFilterBindingPtr *fa = (virNWFilterBindingPtr *) a;
    virNWFilterBindingPtr *fb = (virNWFilterBindingPtr *) b;

    if (*fa && !*fb)
        return -1;

    if (!*fa)
        return *fb != NULL;

    return vshStrcasecmp(virNWFilterBindingGetPortDev(*fa),
                         virNWFilterBindingGetPortDev(*fb));
}


struct virshNWFilterBindingList {
    virNWFilterBindingPtr *bindings;
    size_t nbindings;
};
typedef struct virshNWFilterBindingList *virshNWFilterBindingListPtr;


static void
virshNWFilterBindingListFree(virshNWFilterBindingListPtr list)
{
    size_t i;

    if (list && list->bindings) {
        for (i = 0; i < list->nbindings; i++) {
            if (list->bindings[i])
                virNWFilterBindingFree(list->bindings[i]);
        }
        VIR_FREE(list->bindings);
    }
    VIR_FREE(list);
}


static virshNWFilterBindingListPtr
virshNWFilterBindingListCollect(vshControl *ctl,
                                unsigned int flags)
{
    virshNWFilterBindingListPtr list = vshMalloc(ctl, sizeof(*list));
    int ret;
    bool success = false;
    virshControlPtr priv = ctl->privData;

    if ((ret = virConnectListAllNWFilterBindings(priv->conn,
                                                 &list->bindings,
                                                 flags)) < 0) {
        /* there was an error during the call */
        vshError(ctl, "%s", _("Failed to list network filter bindings"));
        goto cleanup;
    }

    list->nbindings = ret;

    /* sort the list */
    if (list->bindings && list->nbindings > 1)
        qsort(list->bindings, list->nbindings,
              sizeof(*list->bindings), virshNWFilterBindingSorter);

    success = true;

 cleanup:
    if (!success) {
        virshNWFilterBindingListFree(list);
        list = NULL;
    }

    return list;
}


/*
 * "nwfilter-binding-list" command
 */
static const vshCmdInfo info_nwfilter_binding_list[] = {
    {.name = "help",
     .data = N_("list network filter bindings")
    },
    {.name = "desc",
     .data = N_("Returns list of network filter bindings.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_nwfilter_binding_list[] = {
    {.name = NULL}
};

static bool
J
Ján Tomko 已提交
719
cmdNWFilterBindingList(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
720 721
{
    size_t i;
722
    bool ret = false;
723
    virshNWFilterBindingListPtr list = NULL;
724
    vshTablePtr table = NULL;
725 726 727 728

    if (!(list = virshNWFilterBindingListCollect(ctl, 0)))
        return false;

729 730 731
    table = vshTableNew(_("Port Dev"), _("Filter"), NULL);
    if (!table)
        goto cleanup;
732 733 734 735

    for (i = 0; i < list->nbindings; i++) {
        virNWFilterBindingPtr binding = list->bindings[i];

736 737 738 739 740
        if (vshTableRowAppend(table,
                              virNWFilterBindingGetPortDev(binding),
                              virNWFilterBindingGetFilterName(binding),
                              NULL) < 0)
            goto cleanup;
741 742
    }

743 744 745 746 747
    vshTablePrintToStdout(table, ctl);

    ret = true;
 cleanup:
    vshTableFree(table);
748
    virshNWFilterBindingListFree(list);
749
    return ret;
750 751 752
}


E
Eric Blake 已提交
753
const vshCmdDef nwfilterCmds[] = {
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    {.name = "nwfilter-define",
     .handler = cmdNWFilterDefine,
     .opts = opts_nwfilter_define,
     .info = info_nwfilter_define,
     .flags = 0
    },
    {.name = "nwfilter-dumpxml",
     .handler = cmdNWFilterDumpXML,
     .opts = opts_nwfilter_dumpxml,
     .info = info_nwfilter_dumpxml,
     .flags = 0
    },
    {.name = "nwfilter-edit",
     .handler = cmdNWFilterEdit,
     .opts = opts_nwfilter_edit,
     .info = info_nwfilter_edit,
     .flags = 0
    },
    {.name = "nwfilter-list",
     .handler = cmdNWFilterList,
     .opts = opts_nwfilter_list,
     .info = info_nwfilter_list,
     .flags = 0
    },
    {.name = "nwfilter-undefine",
     .handler = cmdNWFilterUndefine,
     .opts = opts_nwfilter_undefine,
     .info = info_nwfilter_undefine,
     .flags = 0
    },
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
    {.name = "nwfilter-binding-create",
     .handler = cmdNWFilterBindingCreate,
     .opts = opts_nwfilter_binding_create,
     .info = info_nwfilter_binding_create,
     .flags = 0
    },
    {.name = "nwfilter-binding-delete",
     .handler = cmdNWFilterBindingDelete,
     .opts = opts_nwfilter_binding_delete,
     .info = info_nwfilter_binding_delete,
     .flags = 0
    },
    {.name = "nwfilter-binding-dumpxml",
     .handler = cmdNWFilterBindingDumpXML,
     .opts = opts_nwfilter_binding_dumpxml,
     .info = info_nwfilter_binding_dumpxml,
     .flags = 0
    },
    {.name = "nwfilter-binding-list",
     .handler = cmdNWFilterBindingList,
     .opts = opts_nwfilter_binding_list,
     .info = info_nwfilter_binding_list,
     .flags = 0
    },
808
    {.name = NULL}
809
};