diff mbox

[RFC,1/9] hostdev: introduce the infrastructure for host device model

Message ID 1332740423-8426-2-git-send-email-zwu.kernel@gmail.com
State New
Headers show

Commit Message

Zhiyong Wu March 26, 2012, 5:40 a.m. UTC
From: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>

Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
---
 include/qemu/hostdev.h |  128 ++++++++++++++++++
 qom/Makefile           |    2 +-
 qom/hostdev.c          |  333 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 462 insertions(+), 1 deletions(-)
 create mode 100644 include/qemu/hostdev.h
 create mode 100644 qom/hostdev.c

Comments

Zhiyong Wu March 26, 2012, 5:54 a.m. UTC | #1
A lot of property get/set functions in qdev-properties.c are related
to DeviceState. So i have to copy and modify some of them here to
apply our host device model. In the future, we should make those
functions more generic.

On Mon, Mar 26, 2012 at 1:40 PM,  <zwu.kernel@gmail.com> wrote:
> From: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
>
> Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
> ---
>  include/qemu/hostdev.h |  128 ++++++++++++++++++
>  qom/Makefile           |    2 +-
>  qom/hostdev.c          |  333 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 462 insertions(+), 1 deletions(-)
>  create mode 100644 include/qemu/hostdev.h
>  create mode 100644 qom/hostdev.c
>
> diff --git a/include/qemu/hostdev.h b/include/qemu/hostdev.h
> new file mode 100644
> index 0000000..a291761
> --- /dev/null
> +++ b/include/qemu/hostdev.h
> @@ -0,0 +1,128 @@
> +/*
> + * QEMU host device model
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + *  Zhi Yong Wu   <wuzhy@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef QEMU_HOSTDEV_H
> +#define QEMU_HOSTDEV_H
> +
> +#include "qemu-queue.h"
> +#include "qemu-char.h"
> +#include "qemu-option.h"
> +#include "qapi/qapi-visit-core.h"
> +#include "qemu/object.h"
> +
> +typedef struct hostdevProperty hostdevProperty;
> +typedef struct hostdevPropertyInfo hostdevPropertyInfo;
> +
> +/**
> + * SECTION: hostdev
> + * @section_id: QEMU-hostdev
> + * @title: hostdev Class
> + * @short_description: Base class for all host devices
> + */
> +
> +typedef struct HOSTDevice HOSTDevice;
> +
> +#define TYPE_HOSTDEV "host-dev"
> +#define HOST_DEVICE(obj) \
> +     OBJECT_CHECK(HOSTDevice, (obj), TYPE_HOSTDEV)
> +#define HOSTDEV_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(HOSTDeviceClass, (klass), TYPE_HOSTDEV)
> +#define HOSTDEV_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(HOSTDeviceClass, (obj), TYPE_HOSTDEV)
> +
> +/**
> + * HOSTDeviceClass:
> + *
> + * Represents a host device model.
> + */
> +typedef struct HOSTDeviceClass {
> +    ObjectClass parent_class;
> +    hostdevProperty *props;
> +
> +    int (*init)(HOSTDevice *host_dv);
> +} HOSTDeviceClass;
> +
> +/**
> + * HOSTDevice:
> + *
> + * State of one host device.
> + */
> +struct HOSTDevice {
> +    /*< private >*/
> +    Object parent_obj;
> +
> +    /*< public >*/
> +};
> +
> +struct hostdevProperty {
> +    const char   *name;
> +    hostdevPropertyInfo *info;
> +    int          offset;
> +    uint8_t      bitnr;
> +    uint8_t      qtype;
> +    int64_t      defval;
> +};
> +
> +struct hostdevPropertyInfo {
> +    const char *name;
> +    const char *legacy_name;
> +    const char **enum_table;
> +    int64_t min;
> +    int64_t max;
> +    int (*parse)(HOSTDevice *dev,
> +                 hostdevProperty *prop,
> +                 const char *str);
> +    int (*print)(HOSTDevice *dev,
> +                 hostdevProperty *prop,
> +                 char *dest,
> +                 size_t len);
> +    ObjectPropertyAccessor *get;
> +    ObjectPropertyAccessor *set;
> +    ObjectPropertyRelease *release;
> +};
> +
> +extern hostdevPropertyInfo hostdev_prop_int32;
> +extern hostdevPropertyInfo hostdev_prop_string;
> +extern hostdevPropertyInfo hostdev_prop_netdev;
> +
> +#define DEFINE_HOSTDEV_PROP(_name, _state, _field, _prop, _type) { \
> +        .name      = (_name),                                    \
> +        .info      = &(_prop),                                   \
> +        .offset    = offsetof(_state, _field)                    \
> +            + type_check(_type,typeof_field(_state, _field)),    \
> +        }
> +#define DEFINE_HOSTDEV_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
> +        .name      = (_name),                                           \
> +        .info      = &(_prop),                                          \
> +        .offset    = offsetof(_state, _field)                           \
> +            + type_check(_type,typeof_field(_state, _field)),           \
> +        .qtype     = QTYPE_QINT,                                        \
> +        .defval    = (_type)_defval,                                    \
> +        }
> +#define DEFINE_HOSTDEV_PROP_END_OF_LIST()               \
> +    {}
> +#define DEFINE_HOSTDEV_PROP_INT32(_n, _s, _f, _d)              \
> +    DEFINE_HOSTDEV_PROP_DEFAULT(_n, _s, _f, _d, hostdev_prop_int32, int32_t)
> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
> +#define DEFINE_HOSTDEV_PROP_STRING(_n, _s, _f)             \
> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_string, char*)
> +
> +HOSTDevice *hostdev_device_create(const char *type);
> +int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id);
> +void hostdev_prop_set_string(HOSTDevice *dev,
> +                             const char *name, char *value);
> +void hostdev_prop_set_peer(HOSTDevice *dev,
> +                           const char *name, NetClientState *value);
> +
> +#endif
> diff --git a/qom/Makefile b/qom/Makefile
> index 34c6de5..4731fb9 100644
> --- a/qom/Makefile
> +++ b/qom/Makefile
> @@ -1,2 +1,2 @@
>  qom-y = object.o container.o qom-qobject.o
> -qom-twice-y = cpu.o
> +qom-twice-y = cpu.o hostdev.o
> diff --git a/qom/hostdev.c b/qom/hostdev.c
> new file mode 100644
> index 0000000..867e869
> --- /dev/null
> +++ b/qom/hostdev.c
> @@ -0,0 +1,333 @@
> +/*
> + * QEMU host device model
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + *  Zhi Yong Wu   <wuzhy@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2 or later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/hostdev.h"
> +#include "qemu-common.h"
> +#include "net.h"
> +
> +void hostdev_prop_set_string(HOSTDevice *dev,
> +                             const char *name, char *value)
> +{
> +    Error *errp = NULL;
> +    object_property_set_str(OBJECT(dev), value, name, &errp);
> +    assert_no_error(errp);
> +}
> +
> +void hostdev_prop_set_peer(HOSTDevice *dev,
> +                           const char *name, NetClientState *value)
> +{
> +    Error *errp = NULL;
> +    assert(!value || value->name);
> +    object_property_set_str(OBJECT(dev),
> +                            value ? value->name : "", name, &errp);
> +    assert_no_error(errp);
> +}
> +
> +static Object *hostdev_get_hostdev(void)
> +{
> +    static Object *dev;
> +
> +    if (dev == NULL) {
> +        dev = object_new("container");
> +        object_property_add_child(object_get_root(), "hostdev",
> +                                  OBJECT(dev), NULL);
> +    }
> +
> +    return dev;
> +}
> +
> +HOSTDevice *hostdev_device_create(const char *type)
> +{
> +    HOSTDevice *hostdev;
> +
> +    hostdev = HOST_DEVICE(object_new(type));
> +    if (!hostdev) {
> +        return NULL;
> +    }
> +
> +    return hostdev;
> +}
> +
> +int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id)
> +{
> +    HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(dev);
> +    gchar *dev_id;
> +    int rc;
> +
> +    rc = dc->init(dev);
> +    if (rc < 0) {
> +        object_delete(OBJECT(dev));
> +        return rc;
> +    }
> +
> +    if (id) {
> +        dev_id = g_strdup(id);
> +    } else {
> +        static int anon_count;
> +        dev_id = g_strdup_printf("%s[%d]", (char *)type, anon_count++);
> +    }
> +
> +    object_property_add_child(hostdev_get_hostdev(), dev_id,
> +                              OBJECT(dev), NULL);
> +    g_free(dev_id);
> +
> +    return 0;
> +}
> +
> +static void *hostdev_get_prop_ptr(HOSTDevice *dev, hostdevProperty *prop)
> +{
> +    void *ptr = dev;
> +    ptr += prop->offset;
> +    return ptr;
> +}
> +
> +static void error_set_from_hostdev_prop_error(Error **errp, int ret,
> +                                              HOSTDevice *dev, hostdevProperty *prop,
> +                                              const char *value)
> +{
> +    switch (ret) {
> +    case -EEXIST:
> +        error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
> +                  object_get_typename(OBJECT(dev)), prop->name, value);
> +        break;
> +    default:
> +    case -EINVAL:
> +        error_set(errp, QERR_PROPERTY_VALUE_BAD,
> +                  object_get_typename(OBJECT(dev)), prop->name, value);
> +        break;
> +    case -ENOENT:
> +        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
> +                  object_get_typename(OBJECT(dev)), prop->name, value);
> +        break;
> +    case 0:
> +        break;
> +    }
> +}
> +
> +/* --- netdev device --- */
> +static void get_pointer(Object *obj, Visitor *v, hostdevProperty *prop,
> +                        const char *(*print)(void *ptr),
> +                        const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    void **ptr = hostdev_get_prop_ptr(dev, prop);
> +    char *p;
> +
> +    p = (char *) (*ptr ? print(*ptr) : "");
> +    visit_type_str(v, &p, name, errp);
> +}
> +
> +static void set_pointer(Object *obj, Visitor *v, hostdevProperty *prop,
> +                        int (*parse)(HOSTDevice *dev, const char *str, void **ptr),
> +                        const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    Error *local_err = NULL;
> +    void **ptr = hostdev_get_prop_ptr(dev, prop);
> +    char *str;
> +    int ret;
> +
> +    visit_type_str(v, &str, name, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    if (!*str) {
> +        g_free(str);
> +        *ptr = NULL;
> +        return;
> +    }
> +    ret = parse(dev, str, ptr);
> +    error_set_from_hostdev_prop_error(errp, ret, dev, prop, str);
> +    g_free(str);
> +}
> +
> +/* --- 32bit integer --- */
> +static void get_int32(Object *obj, Visitor *v, void *opaque,
> +                      const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    hostdevProperty *prop = opaque;
> +    int32_t *ptr = hostdev_get_prop_ptr(dev, prop);
> +    int64_t value;
> +
> +    value = *ptr;
> +    visit_type_int(v, &value, name, errp);
> +}
> +
> +static void set_int32(Object *obj, Visitor *v, void *opaque,
> +                      const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    hostdevProperty *prop = opaque;
> +    int32_t *ptr = hostdev_get_prop_ptr(dev, prop);
> +    Error *local_err = NULL;
> +    int64_t value;
> +
> +    visit_type_int(v, &value, name, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    if (value >= prop->info->min && value <= prop->info->max) {
> +        *ptr = value;
> +    } else {
> +        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
> +                  "", name, value, prop->info->min,
> +                  prop->info->max);
> +    }
> +}
> +
> +hostdevPropertyInfo hostdev_prop_int32 = {
> +    .name  = "int32",
> +    .get   = get_int32,
> +    .set   = set_int32,
> +    .min   = -0x80000000LL,
> +    .max   = 0x7FFFFFFFLL,
> +};
> +
> +/* --- netdev --- */
> +static int parse_netdev(HOSTDevice *dev, const char *str, void **ptr)
> +{
> +    NetClientState *netdev = qemu_find_netdev(str);
> +
> +    if (netdev == NULL) {
> +        return -ENOENT;
> +    }
> +    if (netdev->peer) {
> +        return -EEXIST;
> +    }
> +    *ptr = netdev;
> +    return 0;
> +}
> +
> +static const char *print_netdev(void *ptr)
> +{
> +    NetClientState *netdev = ptr;
> +
> +    return netdev->name ? netdev->name : "";
> +}
> +
> +static void get_netdev(Object *obj, Visitor *v, void *opaque,
> +                       const char *name, Error **errp)
> +{
> +    get_pointer(obj, v, opaque, print_netdev, name, errp);
> +}
> +
> +static void set_netdev(Object *obj, Visitor *v, void *opaque,
> +                       const char *name, Error **errp)
> +{
> +    set_pointer(obj, v, opaque, parse_netdev, name, errp);
> +}
> +
> +hostdevPropertyInfo hostdev_prop_netdev = {
> +    .name  = "peer",
> +    .get   = get_netdev,
> +    .set   = set_netdev,
> +};
> +
> +/* --- string --- */
> +static void release_string(Object *obj, const char *name, void *opaque)
> +{
> +    hostdevProperty *prop = opaque;
> +    g_free(*(char **)hostdev_get_prop_ptr(HOST_DEVICE(obj), prop));
> +}
> +
> +static void get_string(Object *obj, Visitor *v, void *opaque,
> +                       const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    hostdevProperty *prop = opaque;
> +    char **ptr = hostdev_get_prop_ptr(dev, prop);
> +
> +    if (!*ptr) {
> +        char *str = (char *)"";
> +        visit_type_str(v, &str, name, errp);
> +    } else {
> +        visit_type_str(v, ptr, name, errp);
> +    }
> +}
> +
> +static void set_string(Object *obj, Visitor *v, void *opaque,
> +                       const char *name, Error **errp)
> +{
> +    HOSTDevice *dev = HOST_DEVICE(obj);
> +    hostdevProperty *prop = opaque;
> +    char **ptr = hostdev_get_prop_ptr(dev, prop);
> +    Error *local_err = NULL;
> +    char *str;
> +
> +    visit_type_str(v, &str, name, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    if (*ptr) {
> +        g_free(*ptr);
> +    }
> +    *ptr = str;
> +}
> +
> +hostdevPropertyInfo hostdev_prop_string = {
> +    .name  = "string",
> +    .release = release_string,
> +    .get   = get_string,
> +    .set   = set_string,
> +};
> +/*
> +static char *hostdev_get_type(Object *obj, Error **errp)
> +{
> +    return g_strdup(object_get_typename(obj));
> +}
> +*/
> +static void hostdev_property_add_static(HOSTDevice *dev, hostdevProperty *prop,
> +                                        Error **errp)
> +{
> +    if (!prop->info->get && !prop->info->set) {
> +        return;
> +    }
> +
> +    object_property_add(OBJECT(dev), prop->name, prop->info->name,
> +                        prop->info->get, prop->info->set,
> +                        prop->info->release,
> +                        prop, errp);
> +}
> +
> +static void hostdev_init(Object *obj)
> +{
> +    HOSTDevice *s = HOST_DEVICE(obj);
> +    HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(obj);
> +    hostdevProperty *prop;
> +
> +    for (prop = dc->props; prop && prop->name; prop++) {
> +        hostdev_property_add_static(s, prop, NULL);
> +    }
> +
> +    //object_property_add_str(OBJECT(s), "type", hostdev_get_type, NULL, NULL);
> +}
> +
> +static TypeInfo hostdev_type_info = {
> +    .name          = TYPE_HOSTDEV,
> +    .parent        = TYPE_OBJECT,
> +    .instance_size = sizeof(HOSTDevice),
> +    .instance_init = hostdev_init,
> +    .abstract      = true,
> +    .class_size    = sizeof(HOSTDeviceClass),
> +};
> +
> +static void hostdev_register_types(void)
> +{
> +    type_register_static(&hostdev_type_info);
> +}
> +
> +type_init(hostdev_register_types)
> --
> 1.7.6
>
Paolo Bonzini March 27, 2012, 8:23 a.m. UTC | #2
Il 26/03/2012 07:40, zwu.kernel@gmail.com ha scritto:
> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)

This should be simply a link<NetDev> property.

Paolo
Zhiyong Wu March 27, 2012, 9:06 a.m. UTC | #3
On Tue, Mar 27, 2012 at 4:23 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 26/03/2012 07:40, zwu.kernel@gmail.com ha scritto:
>> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>
> This should be simply a link<NetDev> property.
IMHO, i don't fully understand what link<NetDev> mean. What is the
difference between it and Child<NetDev>. Can you elaborate this?

>
> Paolo
Paolo Bonzini March 27, 2012, 10:15 a.m. UTC | #4
Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>> >> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>> >> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>> >
>> > This should be simply a link<NetDev> property.
> IMHO, i don't fully understand what link<NetDev> mean. What is the
> difference between it and Child<NetDev>. Can you elaborate this?

link<NetDev> is a pointer to another object.  child<NetDev> means that
you effectively embed the other object.  You die, the other object dies.

Your QOMification should also convert NICState to QOM.  The NICState
will be a child of the NIC device, and similar for all other
NetClientStates.  I'm not sure why you are not converting qemu_new_nic
to QOM, since NICState is-a NetClientState.

I think this conversion is extremely premature, for multiple reasons.

1) together with each conversion, we should make sure that each object
has a canonical path.  Without a canonical path you cannot use
object_property_set_link, for example.  So far, not even board-level
devices have a canonical path.  I'll bump this towards the top of my list.

2) the network devices subsystem is among the most complicated.  There
is already a pending refactoring for hubs; you are making these changes
on top of hubs but didn't even state this anywhere.  Let's concentrate
on one thing at a time, please.

3) the network devices already support hotplug very well, so it's also
not too useful to do them first.  Let's first do chardevs.

Paolo
Zhiyong Wu March 27, 2012, 11:59 a.m. UTC | #5
On Tue, Mar 27, 2012 at 6:15 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>>> >> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>>> >> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>>> >
>>> > This should be simply a link<NetDev> property.
>> IMHO, i don't fully understand what link<NetDev> mean. What is the
>> difference between it and Child<NetDev>. Can you elaborate this?
>
> link<NetDev> is a pointer to another object.  child<NetDev> means that
Where are link<NetDev> used? what is relationship between the two
objects? it represent the relation between bus object and device
object?

> you effectively embed the other object.  You die, the other object dies.
>
> Your QOMification should also convert NICState to QOM.  The NICState
> will be a child of the NIC device, and similar for all other
> NetClientStates.  I'm not sure why you are not converting qemu_new_nic
We will not convert -net to QOM, that is, we don't care -net nic.
Moreover, -device has exposed network card info.
> to QOM, since NICState is-a NetClientState.
>
> I think this conversion is extremely premature, for multiple reasons.
>
> 1) together with each conversion, we should make sure that each object
> has a canonical path.  Without a canonical path you cannot use
> object_property_set_link, for example.  So far, not even board-level
> devices have a canonical path.  I'll bump this towards the top of my list.
>
> 2) the network devices subsystem is among the most complicated.  There
> is already a pending refactoring for hubs; you are making these changes
> on top of hubs but didn't even state this anywhere.  Let's concentrate
> on one thing at a time, please.
good advice. thanks
>
> 3) the network devices already support hotplug very well, so it's also
> not too useful to do them first.  Let's first do chardevs.
We hope that -netdev options info can be configurated or changed
purely via QOM, not command line.
>
> Paolo
Paolo Bonzini March 27, 2012, 1:58 p.m. UTC | #6
Il 27/03/2012 13:59, Zhi Yong Wu ha scritto:
> On Tue, Mar 27, 2012 at 6:15 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>>>>>> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>>>>>> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>>>>>
>>>>> This should be simply a link<NetDev> property.
>>> IMHO, i don't fully understand what link<NetDev> mean. What is the
>>> difference between it and Child<NetDev>. Can you elaborate this?
>>
>> link<NetDev> is a pointer to another object.  child<NetDev> means that
> Where are link<NetDev> used?

The peer property needs to be one.

> what is relationship between the two objects?

A has a pointer to B.

> it represent the relation between bus object and device object?

We're talking about netdevs, bus and object does not matter here no?

> We will not convert -net to QOM, that is, we don't care -net nic.

As long as it works that's fine but...

> Moreover, -device has exposed network card info.

... this is extremely confused.  Each NIC device has a NIC-type
NetClientState.  If NetClientState is converted to QOM, all of its
instances should be QOM objects, including those owned by NICs.

>> 3) the network devices already support hotplug very well, so it's also
>> not too useful to do them first.  Let's first do chardevs.
> 
> We hope that -netdev options info can be configurated or changed
> purely via QOM, not command line.

Yes, but does it buy anything or it is just a nice exercise?

Paolo
Zhiyong Wu March 27, 2012, 2:18 p.m. UTC | #7
On Tue, Mar 27, 2012 at 9:58 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 27/03/2012 13:59, Zhi Yong Wu ha scritto:
>> On Tue, Mar 27, 2012 at 6:15 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>>>>>>> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>>>>>>> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>>>>>>
>>>>>> This should be simply a link<NetDev> property.
>>>> IMHO, i don't fully understand what link<NetDev> mean. What is the
>>>> difference between it and Child<NetDev>. Can you elaborate this?
>>>
>>> link<NetDev> is a pointer to another object.  child<NetDev> means that
>> Where are link<NetDev> used?
>
> The peer property needs to be one.
sorry, i don't get what it means.
>
>> what is relationship between the two objects?
>
> A has a pointer to B.
I knew this, but can you say one example in QEMU device model? I
checked QEMU code, and found that those link functions in object.c are
not currently used. right?
>
>> it represent the relation between bus object and device object?
>
> We're talking about netdevs, bus and object does not matter here no?
yeah.
>
>> We will not convert -net to QOM, that is, we don't care -net nic.
>
> As long as it works that's fine but...
>
>> Moreover, -device has exposed network card info.
>
> ... this is extremely confused.  Each NIC device has a NIC-type
> NetClientState.  If NetClientState is converted to QOM, all of its
The original idea about -netdev QOM is to convert NetClientState to
QOM, but now this idea seems to be changed.
> instances should be QOM objects, including those owned by NICs.
>
>>> 3) the network devices already support hotplug very well, so it's also
>>> not too useful to do them first.  Let's first do chardevs.
>>
>> We hope that -netdev options info can be configurated or changed
>> purely via QOM, not command line.
>
> Yes, but does it buy anything or it is just a nice exercise?
buy anything? sorry, i don't understand this.
>
> Paolo
Paolo Bonzini March 27, 2012, 2:50 p.m. UTC | #8
Il 27/03/2012 16:18, Zhi Yong Wu ha scritto:
> On Tue, Mar 27, 2012 at 9:58 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 27/03/2012 13:59, Zhi Yong Wu ha scritto:
>>> On Tue, Mar 27, 2012 at 6:15 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>> Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>>>>>>>> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>>>>>>>> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>>>>>>>
>>>>>>> This should be simply a link<NetDev> property.
>>>>> IMHO, i don't fully understand what link<NetDev> mean. What is the
>>>>> difference between it and Child<NetDev>. Can you elaborate this?
>>>>
>>>> link<NetDev> is a pointer to another object.  child<NetDev> means that
>>> Where are link<NetDev> used?
>>
>> The peer property needs to be one.
> sorry, i don't get what it means.

Links are pointers.  As you convert host devices to QOM, pointer
properties such as drive or chardev need to become links.  Peer is
another pointer property that needs to become a link.

>>> what is relationship between the two objects?
>>
>> A has a pointer to B.
>
> I knew this, but can you say one example in QEMU device model? I
> checked QEMU code, and found that those link functions in object.c are
> not currently used. right?

Yes, that's correct.  Everything that uses PROP_PTR needs to become a
link.  We cannot do that yet because devices do not yet have a canonical
path.

>>> Moreover, -device has exposed network card info.
>>
>> ... this is extremely confused.  Each NIC device has a NIC-type
>> NetClientState.  If NetClientState is converted to QOM, all of its
> The original idea about -netdev QOM is to convert NetClientState to
> QOM, but now this idea seems to be changed.

I cannot parse this at all.  You have not converted all of
NetClientState to QOM, have you?

>>> We hope that -netdev options info can be configurated or changed
>>> purely via QOM, not command line.
>>
>> Yes, but does it buy anything or it is just a nice exercise?
> 
> buy anything? sorry, i don't understand this.

What's the advantage?  Converting chardev would give hotplug.  What can
we do with a QOMified netdev that we cannot do now?

Paolo
Zhiyong Wu March 27, 2012, 9:21 p.m. UTC | #9
On Tue, Mar 27, 2012 at 10:50 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 27/03/2012 16:18, Zhi Yong Wu ha scritto:
>> On Tue, Mar 27, 2012 at 9:58 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> Il 27/03/2012 13:59, Zhi Yong Wu ha scritto:
>>>> On Tue, Mar 27, 2012 at 6:15 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>> Il 27/03/2012 11:06, Zhi Yong Wu ha scritto:
>>>>>>>>>> +#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
>>>>>>>>>> +    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
>>>>>>>>
>>>>>>>> This should be simply a link<NetDev> property.
>>>>>> IMHO, i don't fully understand what link<NetDev> mean. What is the
>>>>>> difference between it and Child<NetDev>. Can you elaborate this?
>>>>>
>>>>> link<NetDev> is a pointer to another object.  child<NetDev> means that
>>>> Where are link<NetDev> used?
>>>
>>> The peer property needs to be one.
>> sorry, i don't get what it means.
>
> Links are pointers.  As you convert host devices to QOM, pointer
> properties such as drive or chardev need to become links.  Peer is
> another pointer property that needs to become a link.
It makes sense to me, thanks.
>
>>>> what is relationship between the two objects?
>>>
>>> A has a pointer to B.
>>
>> I knew this, but can you say one example in QEMU device model? I
>> checked QEMU code, and found that those link functions in object.c are
>> not currently used. right?
>
> Yes, that's correct.  Everything that uses PROP_PTR needs to become a
But i didn't see that that stuff which uses PROP_PTR become a link in
current QEMU code.
For example:
static Property apic_properties_common[] = {
  ......
    DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env),
  .....
    DEFINE_PROP_END_OF_LIST(),
};

It define one PROP_PTR cpu_env, but i didn't see stuff which made it
become one link. Did i miss anything?

> link.  We cannot do that yet because devices do not yet have a canonical
> path.
Cannonical path means that it is one absolute path or partial path?
>
>>>> Moreover, -device has exposed network card info.
>>>
>>> ... this is extremely confused.  Each NIC device has a NIC-type
>>> NetClientState.  If NetClientState is converted to QOM, all of its
>> The original idea about -netdev QOM is to convert NetClientState to
>> QOM, but now this idea seems to be changed.
>
> I cannot parse this at all.  You have not converted all of
> NetClientState to QOM, have you?
No. I am not sure if we need to convert all and we need to know what
the benefit is.
>
>>>> We hope that -netdev options info can be configurated or changed
>>>> purely via QOM, not command line.
>>>
>>> Yes, but does it buy anything or it is just a nice exercise?
>>
>> buy anything? sorry, i don't understand this.
>
> What's the advantage?  Converting chardev would give hotplug.  What can
> we do with a QOMified netdev that we cannot do now?
It can be configurated or changed purely via QOM, this is one of the
advantages by itself. And I think that it should also give hotplug.
>
> Paolo
Paolo Bonzini March 28, 2012, 6:41 a.m. UTC | #10
Il 27/03/2012 23:21, Zhi Yong Wu ha scritto:
>> Yes, that's correct.  Everything that uses PROP_PTR needs to become a
> But i didn't see that that stuff which uses PROP_PTR become a link in
> current QEMU code.

Yes, that's why I wrote "needs to become".  In order to use links, you
need two things:

* the target needs to have a canonical path (more on this below);

* the target needs to be QOMified.

Most PTR properties are pointers to devices, but devices so far don't
always have a canonical path so the conversion could not happen.  Others
are to CPUs, which are not yet QOMified.

>> link.  We cannot do that yet because devices do not yet have a canonical
>> path.
> Cannonical path means that it is one absolute path or partial path?

Canonical path means it consists exclusively of child<> properties.
Unlike the links, which form a graph, children form a tree so it's easy
to define a canonical naming of all objects.

>>>>> Moreover, -device has exposed network card info.
>>>>
>>>> ... this is extremely confused.  Each NIC device has a NIC-type
>>>> NetClientState.  If NetClientState is converted to QOM, all of its
>>> The original idea about -netdev QOM is to convert NetClientState to
>>> QOM, but now this idea seems to be changed.
>>
>> I cannot parse this at all.  You have not converted all of
>> NetClientState to QOM, have you?
> No. I am not sure if we need to convert all and we need to know what
> the benefit is.

We do.  You just cannot convert the same object half to QOM and half
not.  It leads to insanity.

>>>>> We hope that -netdev options info can be configurated or changed
>>>>> purely via QOM, not command line.
>>>>
>>>> Yes, but does it buy anything or it is just a nice exercise?
>>>
>>> buy anything? sorry, i don't understand this.
>>
>> What's the advantage?  Converting chardev would give hotplug.  What can
>> we do with a QOMified netdev that we cannot do now?
> It can be configurated or changed purely via QOM, this is one of the
> advantages by itself.

Sure, but what does it do better than netdev_add?

Note that the same holds for devices.  Anthony converted them as the
proof that QOM could deal with them, and that conversions could be done
in small steps.  But strictly speaking it was not necessary to convert
them to QOM; so far, conversion brought no substantial improvement.

> And I think that it should also give hotplug.

Hotplug of -netdev is already supported.

Paolo
Zhiyong Wu March 28, 2012, 7:50 a.m. UTC | #11
On Wed, Mar 28, 2012 at 2:41 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 27/03/2012 23:21, Zhi Yong Wu ha scritto:
>>> Yes, that's correct.  Everything that uses PROP_PTR needs to become a
>> But i didn't see that that stuff which uses PROP_PTR become a link in
>> current QEMU code.
>
> Yes, that's why I wrote "needs to become".  In order to use links, you
> need two things:
>
> * the target needs to have a canonical path (more on this below);
>
> * the target needs to be QOMified.
>
> Most PTR properties are pointers to devices, but devices so far don't
> always have a canonical path so the conversion could not happen.  Others
> are to CPUs, which are not yet QOMified.
nice, got it. link is next step for PROP_PTR, thanks
>
>>> link.  We cannot do that yet because devices do not yet have a canonical
>>> path.
>> Cannonical path means that it is one absolute path or partial path?
>
> Canonical path means it consists exclusively of child<> properties.
> Unlike the links, which form a graph, children form a tree so it's easy
> to define a canonical naming of all objects.
>
>>>>>> Moreover, -device has exposed network card info.
>>>>>
>>>>> ... this is extremely confused.  Each NIC device has a NIC-type
>>>>> NetClientState.  If NetClientState is converted to QOM, all of its
>>>> The original idea about -netdev QOM is to convert NetClientState to
>>>> QOM, but now this idea seems to be changed.
>>>
>>> I cannot parse this at all.  You have not converted all of
>>> NetClientState to QOM, have you?
>> No. I am not sure if we need to convert all and we need to know what
>> the benefit is.
>
> We do.  You just cannot convert the same object half to QOM and half
> not.  It leads to insanity.
OK, i will convert all.
>
>>>>>> We hope that -netdev options info can be configurated or changed
>>>>>> purely via QOM, not command line.
>>>>>
>>>>> Yes, but does it buy anything or it is just a nice exercise?
>>>>
>>>> buy anything? sorry, i don't understand this.
>>>
>>> What's the advantage?  Converting chardev would give hotplug.  What can
>>> we do with a QOMified netdev that we cannot do now?
>> It can be configurated or changed purely via QOM, this is one of the
>> advantages by itself.
>
> Sure, but what does it do better than netdev_add?
If -netdev QOM is supported, libvirt can use non-root account to get
some service from QEMU. this will enforce security, right?
>
> Note that the same holds for devices.  Anthony converted them as the
> proof that QOM could deal with them, and that conversions could be done
> in small steps.  But strictly speaking it was not necessary to convert
> them to QOM; so far, conversion brought no substantial improvement.
>
>> And I think that it should also give hotplug.
>
> Hotplug of -netdev is already supported.
ah? IHMO, i have limited knowledge about QOM, and don't know why you
said that chardev QOM can provide hotplug, how to play with it?

>
> Paolo
Zhiyong Wu March 28, 2012, 7:53 a.m. UTC | #12
By the way, why have we not add one QOM cookbook to docs? It is very
useful for us newbiew to learn.

On Wed, Mar 28, 2012 at 2:41 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 27/03/2012 23:21, Zhi Yong Wu ha scritto:
>>> Yes, that's correct.  Everything that uses PROP_PTR needs to become a
>> But i didn't see that that stuff which uses PROP_PTR become a link in
>> current QEMU code.
>
> Yes, that's why I wrote "needs to become".  In order to use links, you
> need two things:
>
> * the target needs to have a canonical path (more on this below);
>
> * the target needs to be QOMified.
>
> Most PTR properties are pointers to devices, but devices so far don't
> always have a canonical path so the conversion could not happen.  Others
> are to CPUs, which are not yet QOMified.
>
>>> link.  We cannot do that yet because devices do not yet have a canonical
>>> path.
>> Cannonical path means that it is one absolute path or partial path?
>
> Canonical path means it consists exclusively of child<> properties.
> Unlike the links, which form a graph, children form a tree so it's easy
> to define a canonical naming of all objects.
>
>>>>>> Moreover, -device has exposed network card info.
>>>>>
>>>>> ... this is extremely confused.  Each NIC device has a NIC-type
>>>>> NetClientState.  If NetClientState is converted to QOM, all of its
>>>> The original idea about -netdev QOM is to convert NetClientState to
>>>> QOM, but now this idea seems to be changed.
>>>
>>> I cannot parse this at all.  You have not converted all of
>>> NetClientState to QOM, have you?
>> No. I am not sure if we need to convert all and we need to know what
>> the benefit is.
>
> We do.  You just cannot convert the same object half to QOM and half
> not.  It leads to insanity.
>
>>>>>> We hope that -netdev options info can be configurated or changed
>>>>>> purely via QOM, not command line.
>>>>>
>>>>> Yes, but does it buy anything or it is just a nice exercise?
>>>>
>>>> buy anything? sorry, i don't understand this.
>>>
>>> What's the advantage?  Converting chardev would give hotplug.  What can
>>> we do with a QOMified netdev that we cannot do now?
>> It can be configurated or changed purely via QOM, this is one of the
>> advantages by itself.
>
> Sure, but what does it do better than netdev_add?
>
> Note that the same holds for devices.  Anthony converted them as the
> proof that QOM could deal with them, and that conversions could be done
> in small steps.  But strictly speaking it was not necessary to convert
> them to QOM; so far, conversion brought no substantial improvement.
>
>> And I think that it should also give hotplug.
>
> Hotplug of -netdev is already supported.
>
> Paolo
Paolo Bonzini March 28, 2012, 8:02 a.m. UTC | #13
Il 28/03/2012 09:53, Zhi Yong Wu ha scritto:
> By the way, why have we not add one QOM cookbook to docs? It is very
> useful for us newbiew to learn.

Yes, that would be useful.  It takes time to write docs unfortunately. :(

Paolo
陳韋任 March 28, 2012, 8:05 a.m. UTC | #14
> Il 28/03/2012 09:53, Zhi Yong Wu ha scritto:
> > By the way, why have we not add one QOM cookbook to docs? It is very
> > useful for us newbiew to learn.

  You can write what you learn during this work. This should be a good
start! :)

Regards,
chenwj
Zhiyong Wu March 28, 2012, 8:25 a.m. UTC | #15
On Wed, Mar 28, 2012 at 4:05 PM, 陳韋任 <chenwj@iis.sinica.edu.tw> wrote:
>> Il 28/03/2012 09:53, Zhi Yong Wu ha scritto:
>> > By the way, why have we not add one QOM cookbook to docs? It is very
>> > useful for us newbiew to learn.
>
>  You can write what you learn during this work. This should be a good
> start! :)
You know, i need to get enough skills now. :)
>
> Regards,
> chenwj
>
> --
> Wei-Ren Chen (陳韋任)
> Computer Systems Lab, Institute of Information Science,
> Academia Sinica, Taiwan (R.O.C.)
> Tel:886-2-2788-3799 #1667
> Homepage: http://people.cs.nctu.edu.tw/~chenwj
陳韋任 March 28, 2012, 8:29 a.m. UTC | #16
On Wed, Mar 28, 2012 at 04:25:54PM +0800, Zhi Yong Wu wrote:
> On Wed, Mar 28, 2012 at 4:05 PM, 陳韋任 <chenwj@iis.sinica.edu.tw> wrote:
> >> Il 28/03/2012 09:53, Zhi Yong Wu ha scritto:
> >> > By the way, why have we not add one QOM cookbook to docs? It is very
> >> > useful for us newbiew to learn.
> >
> >  You can write what you learn during this work. This should be a good
> > start! :)
> You know, i need to get enough skills now. :)

  I mean make some notes during the work. Good luck!

Regards,
chenwj
diff mbox

Patch

diff --git a/include/qemu/hostdev.h b/include/qemu/hostdev.h
new file mode 100644
index 0000000..a291761
--- /dev/null
+++ b/include/qemu/hostdev.h
@@ -0,0 +1,128 @@ 
+/*
+ * QEMU host device model
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Zhi Yong Wu   <wuzhy@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_HOSTDEV_H
+#define QEMU_HOSTDEV_H
+
+#include "qemu-queue.h"
+#include "qemu-char.h"
+#include "qemu-option.h"
+#include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
+
+typedef struct hostdevProperty hostdevProperty;
+typedef struct hostdevPropertyInfo hostdevPropertyInfo;
+
+/**
+ * SECTION: hostdev
+ * @section_id: QEMU-hostdev
+ * @title: hostdev Class
+ * @short_description: Base class for all host devices
+ */
+
+typedef struct HOSTDevice HOSTDevice;
+
+#define TYPE_HOSTDEV "host-dev"
+#define HOST_DEVICE(obj) \
+     OBJECT_CHECK(HOSTDevice, (obj), TYPE_HOSTDEV)
+#define HOSTDEV_CLASS(klass) \
+     OBJECT_CLASS_CHECK(HOSTDeviceClass, (klass), TYPE_HOSTDEV)
+#define HOSTDEV_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(HOSTDeviceClass, (obj), TYPE_HOSTDEV)
+
+/**
+ * HOSTDeviceClass:
+ *
+ * Represents a host device model.
+ */
+typedef struct HOSTDeviceClass {
+    ObjectClass parent_class;
+    hostdevProperty *props;
+
+    int (*init)(HOSTDevice *host_dv);
+} HOSTDeviceClass;
+
+/**
+ * HOSTDevice:
+ *
+ * State of one host device.
+ */
+struct HOSTDevice {
+    /*< private >*/
+    Object parent_obj;
+
+    /*< public >*/
+};
+
+struct hostdevProperty {
+    const char   *name;
+    hostdevPropertyInfo *info;
+    int          offset;
+    uint8_t      bitnr;
+    uint8_t      qtype;
+    int64_t      defval;
+};
+
+struct hostdevPropertyInfo {
+    const char *name;
+    const char *legacy_name;
+    const char **enum_table;
+    int64_t min;
+    int64_t max;
+    int (*parse)(HOSTDevice *dev,
+                 hostdevProperty *prop,
+                 const char *str);
+    int (*print)(HOSTDevice *dev,
+                 hostdevProperty *prop,
+                 char *dest,
+                 size_t len);
+    ObjectPropertyAccessor *get;
+    ObjectPropertyAccessor *set;
+    ObjectPropertyRelease *release;
+};
+
+extern hostdevPropertyInfo hostdev_prop_int32;
+extern hostdevPropertyInfo hostdev_prop_string;
+extern hostdevPropertyInfo hostdev_prop_netdev;
+
+#define DEFINE_HOSTDEV_PROP(_name, _state, _field, _prop, _type) { \
+        .name      = (_name),                                    \
+        .info      = &(_prop),                                   \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(_type,typeof_field(_state, _field)),    \
+        }
+#define DEFINE_HOSTDEV_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
+        .name      = (_name),                                           \
+        .info      = &(_prop),                                          \
+        .offset    = offsetof(_state, _field)                           \
+            + type_check(_type,typeof_field(_state, _field)),           \
+        .qtype     = QTYPE_QINT,                                        \
+        .defval    = (_type)_defval,                                    \
+        }
+#define DEFINE_HOSTDEV_PROP_END_OF_LIST()               \
+    {}
+#define DEFINE_HOSTDEV_PROP_INT32(_n, _s, _f, _d)              \
+    DEFINE_HOSTDEV_PROP_DEFAULT(_n, _s, _f, _d, hostdev_prop_int32, int32_t)
+#define DEFINE_HOSTDEV_PROP_PEER(_n, _s, _f)             \
+    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_netdev, NetClientState*)
+#define DEFINE_HOSTDEV_PROP_STRING(_n, _s, _f)             \
+    DEFINE_HOSTDEV_PROP(_n, _s, _f, hostdev_prop_string, char*)
+
+HOSTDevice *hostdev_device_create(const char *type);
+int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id);
+void hostdev_prop_set_string(HOSTDevice *dev,
+                             const char *name, char *value);
+void hostdev_prop_set_peer(HOSTDevice *dev,
+                           const char *name, NetClientState *value);
+
+#endif
diff --git a/qom/Makefile b/qom/Makefile
index 34c6de5..4731fb9 100644
--- a/qom/Makefile
+++ b/qom/Makefile
@@ -1,2 +1,2 @@ 
 qom-y = object.o container.o qom-qobject.o
-qom-twice-y = cpu.o
+qom-twice-y = cpu.o hostdev.o
diff --git a/qom/hostdev.c b/qom/hostdev.c
new file mode 100644
index 0000000..867e869
--- /dev/null
+++ b/qom/hostdev.c
@@ -0,0 +1,333 @@ 
+/*
+ * QEMU host device model
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Zhi Yong Wu   <wuzhy@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu/hostdev.h"
+#include "qemu-common.h"
+#include "net.h"
+
+void hostdev_prop_set_string(HOSTDevice *dev,
+                             const char *name, char *value)
+{
+    Error *errp = NULL;
+    object_property_set_str(OBJECT(dev), value, name, &errp);
+    assert_no_error(errp);
+}
+
+void hostdev_prop_set_peer(HOSTDevice *dev,
+                           const char *name, NetClientState *value)
+{
+    Error *errp = NULL;
+    assert(!value || value->name);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->name : "", name, &errp);
+    assert_no_error(errp);
+}
+
+static Object *hostdev_get_hostdev(void)
+{
+    static Object *dev;
+
+    if (dev == NULL) {
+        dev = object_new("container");
+        object_property_add_child(object_get_root(), "hostdev",
+                                  OBJECT(dev), NULL);
+    }
+
+    return dev;
+}
+
+HOSTDevice *hostdev_device_create(const char *type)
+{
+    HOSTDevice *hostdev;
+
+    hostdev = HOST_DEVICE(object_new(type));
+    if (!hostdev) {
+        return NULL;
+    }
+
+    return hostdev;
+}
+
+int hostdev_device_init(HOSTDevice *dev, const char *type, const char *id)
+{
+    HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(dev);
+    gchar *dev_id;
+    int rc;
+
+    rc = dc->init(dev);
+    if (rc < 0) {
+        object_delete(OBJECT(dev));
+        return rc;
+    }
+
+    if (id) {
+        dev_id = g_strdup(id);
+    } else {
+        static int anon_count;
+        dev_id = g_strdup_printf("%s[%d]", (char *)type, anon_count++);
+    }
+
+    object_property_add_child(hostdev_get_hostdev(), dev_id,
+                              OBJECT(dev), NULL);
+    g_free(dev_id);
+
+    return 0;
+}
+
+static void *hostdev_get_prop_ptr(HOSTDevice *dev, hostdevProperty *prop)
+{
+    void *ptr = dev;
+    ptr += prop->offset;
+    return ptr;
+}
+
+static void error_set_from_hostdev_prop_error(Error **errp, int ret,
+                                              HOSTDevice *dev, hostdevProperty *prop,
+                                              const char *value)
+{
+    switch (ret) {
+    case -EEXIST:
+        error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    default:
+    case -EINVAL:
+        error_set(errp, QERR_PROPERTY_VALUE_BAD,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    case -ENOENT:
+        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    case 0:
+        break;
+    }
+}
+
+/* --- netdev device --- */
+static void get_pointer(Object *obj, Visitor *v, hostdevProperty *prop,
+                        const char *(*print)(void *ptr),
+                        const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    void **ptr = hostdev_get_prop_ptr(dev, prop);
+    char *p;
+
+    p = (char *) (*ptr ? print(*ptr) : "");
+    visit_type_str(v, &p, name, errp);
+}
+
+static void set_pointer(Object *obj, Visitor *v, hostdevProperty *prop,
+                        int (*parse)(HOSTDevice *dev, const char *str, void **ptr),
+                        const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    Error *local_err = NULL;
+    void **ptr = hostdev_get_prop_ptr(dev, prop);
+    char *str;
+    int ret;
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (!*str) {
+        g_free(str);
+        *ptr = NULL;
+        return;
+    }
+    ret = parse(dev, str, ptr);
+    error_set_from_hostdev_prop_error(errp, ret, dev, prop, str);
+    g_free(str);
+}
+
+/* --- 32bit integer --- */
+static void get_int32(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    hostdevProperty *prop = opaque;
+    int32_t *ptr = hostdev_get_prop_ptr(dev, prop);
+    int64_t value;
+
+    value = *ptr;
+    visit_type_int(v, &value, name, errp);
+}
+
+static void set_int32(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    hostdevProperty *prop = opaque;
+    int32_t *ptr = hostdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (value >= prop->info->min && value <= prop->info->max) {
+        *ptr = value;
+    } else {
+        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+                  "", name, value, prop->info->min,
+                  prop->info->max);
+    }
+}
+
+hostdevPropertyInfo hostdev_prop_int32 = {
+    .name  = "int32",
+    .get   = get_int32,
+    .set   = set_int32,
+    .min   = -0x80000000LL,
+    .max   = 0x7FFFFFFFLL,
+};
+
+/* --- netdev --- */
+static int parse_netdev(HOSTDevice *dev, const char *str, void **ptr)
+{
+    NetClientState *netdev = qemu_find_netdev(str);
+
+    if (netdev == NULL) {
+        return -ENOENT;
+    }
+    if (netdev->peer) {
+        return -EEXIST;
+    }
+    *ptr = netdev;
+    return 0;
+}
+
+static const char *print_netdev(void *ptr)
+{
+    NetClientState *netdev = ptr;
+
+    return netdev->name ? netdev->name : "";
+}
+
+static void get_netdev(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    get_pointer(obj, v, opaque, print_netdev, name, errp);
+}
+
+static void set_netdev(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    set_pointer(obj, v, opaque, parse_netdev, name, errp);
+}
+
+hostdevPropertyInfo hostdev_prop_netdev = {
+    .name  = "peer",
+    .get   = get_netdev,
+    .set   = set_netdev,
+};
+
+/* --- string --- */
+static void release_string(Object *obj, const char *name, void *opaque)
+{
+    hostdevProperty *prop = opaque;
+    g_free(*(char **)hostdev_get_prop_ptr(HOST_DEVICE(obj), prop));
+}
+
+static void get_string(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    hostdevProperty *prop = opaque;
+    char **ptr = hostdev_get_prop_ptr(dev, prop);
+
+    if (!*ptr) {
+        char *str = (char *)"";
+        visit_type_str(v, &str, name, errp);
+    } else {
+        visit_type_str(v, ptr, name, errp);
+    }
+}
+
+static void set_string(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    HOSTDevice *dev = HOST_DEVICE(obj);
+    hostdevProperty *prop = opaque;
+    char **ptr = hostdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
+    char *str;
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (*ptr) {
+        g_free(*ptr);
+    }
+    *ptr = str;
+}
+
+hostdevPropertyInfo hostdev_prop_string = {
+    .name  = "string",
+    .release = release_string,
+    .get   = get_string,
+    .set   = set_string,
+};
+/*
+static char *hostdev_get_type(Object *obj, Error **errp)
+{
+    return g_strdup(object_get_typename(obj));
+}
+*/
+static void hostdev_property_add_static(HOSTDevice *dev, hostdevProperty *prop,
+                                        Error **errp)
+{
+    if (!prop->info->get && !prop->info->set) {
+        return;
+    }
+
+    object_property_add(OBJECT(dev), prop->name, prop->info->name,
+                        prop->info->get, prop->info->set,
+                        prop->info->release,
+                        prop, errp);
+}
+
+static void hostdev_init(Object *obj)
+{
+    HOSTDevice *s = HOST_DEVICE(obj);
+    HOSTDeviceClass *dc = HOSTDEV_GET_CLASS(obj);
+    hostdevProperty *prop;
+
+    for (prop = dc->props; prop && prop->name; prop++) {
+        hostdev_property_add_static(s, prop, NULL);
+    }
+
+    //object_property_add_str(OBJECT(s), "type", hostdev_get_type, NULL, NULL);
+}
+
+static TypeInfo hostdev_type_info = {
+    .name          = TYPE_HOSTDEV,
+    .parent        = TYPE_OBJECT,
+    .instance_size = sizeof(HOSTDevice),
+    .instance_init = hostdev_init,
+    .abstract      = true,
+    .class_size    = sizeof(HOSTDeviceClass),
+};
+
+static void hostdev_register_types(void)
+{
+    type_register_static(&hostdev_type_info);
+}
+
+type_init(hostdev_register_types)