[libvirt] [PATCH] dissectors: Create dissector for Libvirt RPC

Daniel P. Berrange berrange at redhat.com
Tue Oct 11 07:26:26 UTC 2011


On Mon, Oct 10, 2011 at 11:54:16AM +0200, Michal Privoznik wrote:
> This patch creates basic dissector for Libvirt RPC. The protocol
> description can be found here:
> 
> http://libvirt.org/internals/rpc.html
> 
> Currently, only packet head dissecting is written. To fully dissect
> packet payloads a more effort is needed, as each function has
> different arguments (in general). However, this can be good
> stepping stone for later expansion. Ideally, a script that
> will generate this dissector from libvirt RPC file would be written.
> ---
> 
> Okay, this patch obviously belongs to wireshark mailing list,
> but before I'll send it there, I guess we should decide if we
> want it there. I mean there are 2 modes/ways for wireshark
> dissectors:
> 1) Place it into wireshark repo as many others.
>    Advantage: wireshark will be shipped with support for libvirt RPC
>    Disadvantage: wireshark will be shipped with support for libvirt RPC
> 
>    In other words, if you look at wireshark releases, they are not
>    as often as ours, so in the end, this dissector will be always one
>    or more step behind current libvirt. But many users will be able
>    to use it right after box open.
> 
> 2) Dissector as plugin
>    Advantage: we can update it as often as we want
>    Disadvantage: users needs to install a plugin
> 
> Personally, I prefer 2) as libvirt RPC is expanded pretty often,
> and I expect this dissector to be used by libvirt developer mainly,
> for who installing a plugin into wireshark can't be a real problem :)

Yeah, option 2) is the one I'd like to see us focus on.

As Dave says, if Wireshark want to include the libvirt plugin
themselves too, that's great, but we need to make sure we ship
one that is guarenteed up2date for it to be most useful to us.


> +static void
> +dissect_libvirt_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
> +{
> +    gint offset = 0;
> +    /* Okay, these are magic constants, but
> +     * they are just offsets where requested
> +     * info is to be found */
> +    guint32 prog = tvb_get_ntohl(tvb, 4);

Although all our version numbers are currently '1', we should
still include the version field for completeness.

> +    guint32 proc = tvb_get_ntohl(tvb, 12);
> +    guint32 type = tvb_get_ntohl(tvb, 16);
> +    guint32 serial = tvb_get_ntohl(tvb, 20);
> +    guint32 status = tvb_get_ntohl(tvb, 24);
> +
> +    col_set_str(pinfo->cinfo, COL_PROTOCOL, "Libvirt");
> +    col_clear(pinfo->cinfo,COL_INFO);
> +    if (prog == REMOTE_PROGRAM)
> +        col_add_fstr(pinfo->cinfo, COL_INFO, "Proc=%s ", val_to_str(proc, remote_procedure_strings, "%d"));
> +    else if (prog == QEMU_PROGRAM)
> +        col_add_fstr(pinfo->cinfo, COL_INFO, "Proc=%s ", val_to_str(proc, qemu_procedure_strings, "%d"));
> +    else
> +        /* unhandeld program */
> +        col_add_fstr(pinfo->cinfo, COL_INFO, "Proc=%u ", proc);
> +
> +    col_append_fstr(pinfo->cinfo, COL_INFO, "Type=%s Status=%s Prog=%s Serial=%u",
> +        val_to_str(type, type_strings, "%d"),
> +        val_to_str(status, status_strings, "%d"),
> +        val_to_str(prog, program_strings, "%x"),
> +        serial);
> +
> +    if (tree) {
> +        proto_item *ti = NULL;
> +        proto_tree *libvirt_tree = NULL;
> +
> +        ti = proto_tree_add_item(tree, proto_libvirt, tvb, 0, -1, FALSE);
> +        libvirt_tree = proto_item_add_subtree(ti, ett_libvirt);
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_length, tvb, offset, 4, FALSE); offset += 4;
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_program, tvb, offset, 4, FALSE); offset += 4;
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_version, tvb, offset, 4, FALSE); offset += 4;
> +        if (prog == REMOTE_PROGRAM)
> +            proto_tree_add_item(libvirt_tree, hf_libvirt_procedure, tvb, offset, 4, FALSE);
> +        else if (prog == QEMU_PROGRAM)
> +            proto_tree_add_item(libvirt_tree, hf_qemu_procedure, tvb, offset, 4, FALSE);
> +        else
> +            /* unhandeld program */
> +            proto_tree_add_none_format(libvirt_tree, -1, tvb, offset, 4, "Unknown proc: %u", proc);
> +        offset += 4;
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_type, tvb, offset, 4, FALSE); offset += 4;
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_serial, tvb, offset, 4, FALSE); offset += 4;
> +        proto_tree_add_item(libvirt_tree, hf_libvirt_status, tvb, offset, 4, FALSE); offset += 4;
> +    }
> +}
> +
> +static guint32 get_message_len(packet_info *pinfo __attribute__((unused)), tvbuff_t *tvb, int offset)
> +{
> +    return tvb_get_ntohl(tvb, offset);
> +}
> +
> +static void
> +dissect_libvirt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
> +{
> +    /* Another magic const - 4; simply, how much bytes
> +     * is needed to tell the length of libvirt packet. */
> +    tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_message_len, dissect_libvirt_message);
> +}
> +
> +
> +void
> +proto_register_libvirt(void)
> +{
> +    static hf_register_info hf[] = {
> +        { &hf_libvirt_length,
> +          { "length", "libvirt.length",
> +            FT_UINT32, BASE_DEC,
> +            NULL, 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_program,
> +          { "program", "libvirt.program",
> +            FT_UINT32, BASE_HEX,
> +            VALS(program_strings), 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_version,
> +          { "version", "libvirt.version",
> +            FT_UINT32, BASE_DEC,
> +            NULL, 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_procedure,
> +          { "procedure", "libvirt.procedure",
> +            FT_INT32, BASE_DEC,
> +            VALS(remote_procedure_strings), 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_type,
> +          { "type", "libvirt.type",
> +            FT_INT32, BASE_DEC,
> +            VALS(type_strings), 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_serial,
> +          { "serial", "libvirt.serial",
> +            FT_UINT32, BASE_DEC,
> +            NULL, 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_libvirt_status,
> +          { "status", "libvirt.status",
> +            FT_INT32, BASE_DEC,
> +            VALS(status_strings), 0x0,
> +            NULL, HFILL}
> +        },
> +        { &hf_qemu_procedure,
> +          { "procedure", "libvirt.procedure",
> +          FT_INT32, BASE_DEC,
> +          VALS(qemu_procedure_strings), 0x0,
> +          NULL, HFILL}
> +        }
> +    };
> +
> +    static gint *ett[] = {
> +        &ett_libvirt
> +    };
> +
> +    proto_libvirt = proto_register_protocol (
> +        "Libvirt", /* name */
> +        "libvirt", /* short name */
> +        "libvirt"  /* abbrev */
> +    );
> +
> +    proto_register_field_array(proto_libvirt, hf, array_length(hf));
> +    proto_register_subtree_array(ett, array_length(ett));
> +}
> +
> +void
> +proto_reg_handoff_foo(void)
> +{
> +    static dissector_handle_t libvirt_handle;
> +
> +    libvirt_handle = create_dissector_handle(dissect_libvirt, proto_libvirt);
> +    dissector_add_uint("tcp.port", LIBVIRT_PORT, libvirt_handle);
> +}

I'm surprised at just how little code is required todo this !


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list