Re: [libvirt] [PATCH] Add virNetlinkNewLink for simplifying virNetDev*Create

2018-09-01 Thread Shi Lei
On 2018-08-31 at 20:02, Erik Skultety wrote:
>On Thu, Aug 30, 2018 at 02:27:05PM +0800, Shi Lei wrote:
>> Thanks for your comments.
>> But I have several questions, please see below...
>>
>> On 2018-08-29 at 19:43, Erik Skultety wrote:
>> >On Thu, Aug 23, 2018 at 12:15:08PM +0800, Shi Lei wrote:
>> >> This patch adds virNetlinkNewLink for simplifying virNetDevMacVLanCreate
>> >> and virNetDevBridgeCreate.
>> >>
>> >> Signed-off-by: Shi Lei 
>> >> ---
>> >
>> >There are multiple changes happening in this patch so it will need to be 
>> >split
>> >into several patches, see below...
>>
>> Okay. Then the v2 series should be like:
>> [patch v2 0/4]:  ... cover ...
>> [patch v2 1/4]:  Add wrapper macros to make code more readable
>> [patch v2 2/4]:  Introduce virNetlinkNewLink
>
>2/4 would come before 1/4 

Okay.

>
>> [patch v2 3/4]:  Replace the implementation of virNetDevBridgeCreate
>> [patch v2 4/4]:  Replace the implementation of virNetDevMacVLanCreate
>
>3/4 + 4/4 would be a single patch 

Okay.

>
>...
>
>> >> +static int
>> >> +virNetDevMacVLanCreateCallback(struct nl_msg *nl_msg, const void *opaque)
>> >> +{
>> >> +    const uint32_t *mode = (const uint32_t *) opaque;
>> >> +    if (!nl_msg || !opaque) {
>> >> +    virReportError(VIR_ERR_INTERNAL_ERROR,
>> >> +   _("nl_msg %p or opaque %p is NULL"),
>> >> +   nl_msg, opaque);
>> >> +    return -1;
>> >> +    }
>> >> +
>> >> +    if (*mode > 0) {
>> >> +    struct nlattr *info_data;
>> >> +    if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
>> >> +    goto buffer_too_small;
>> >> +
>> >> +    if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(*mode), mode) < 0)
>> >> +    goto buffer_too_small;
>> >> +
>> >> +    nla_nest_end(nl_msg, info_data);
>> >> +    }
>> >> +
>> >> +    return 0;
>> >> +
>> >> + buffer_too_small:
>> >> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> >> +   _("allocated netlink buffer is too small"));
>> >> +    return -1;
>> >> +}
>> >
>> >Having a callback just to add a nested data into nl_msg doesn't feel like 
>> >the
>> >right approach, I'd expect a callback to do more specific stuff, this 
>> >should be
>> >special-cased in virNetlinkNewLink.
>>
>> I looked through the code for ip-link in iproute2 which could be a good 
>> example
>> for netlink. And I found that the differences of attributes of various 
>> net-devices are
>> confined to IFLA_INFO_DATA or IFLA_INFO_SLAVE_DATA(this is not used in 
>> libvirt).
>> The code fragment in iplink.c:
>>
>>         if (ulinep && !strcmp(ulinep, "_slave")) {
>>             ... ...
>>             lu = get_link_slave_kind(slavebuf);
>>             iflatype = IFLA_INFO_SLAVE_DATA;
>>         } else {
>> =>       lu = get_link_kind(type);             /* Get pointer to the driver 
>> for this type */
>> =>       iflatype = IFLA_INFO_DATA;       /* NEST will be for IFLA_INFO_DATA 
>> */
>>         }
>>         if (lu && argc) {
>> =>       struct rtattr *data = addattr_nest(, sizeof(req), iflatype);  
>>   /* NEST BEGIN */
>>
>>             
>>             if (lu->parse_opt &&
>>                 lu->parse_opt(lu, argc, argv, ))
>>                 return -1;
>>             
>>             ^The lu points to various types of net-drivers(e.g. 
>> macvlan/bridge/vxlan/vlan ...)
>>                which pack all special self-attributes in their parse_opt 
>> callback
>>
>> =>        addattr_nest_end(, data);    /* NEST END */
>>
>> So I think that it's reasonable for us to have a callback to handle it just 
>> as iproute2
>> since iproute2 could almost create all the types of net-devices.
>
>I went through the iproute2 code and it completely makes sense for them to
>utilize callbacks here, given the amount of driver-specific options each of the
>device type has. While I agree that we could make use of this in libvirt one
>day, I don't feel like we need to do it now, since I don't think it brings
>any noticeable benefit in its currently proposed form + as I already mentioned,
>we can switch to this scheme once there are more than 1 netlink types which
>could make use of it. 

Okay.

>
>>
>> >
>> >> +
>> >> +
>> >>  /**
>> >>   * virNetDevMacVLanCreate:
>> >>   *
>> >> @@ -307,113 +338,29 @@ virNetDevMacVLanCreate(const char *ifname,
>> >> uint32_t macvlan_mode,
>> >> int *retry)
>> >>  {
>> >
>> >^This replacement would be the last patch in the series.
>>
>> Okay.
>>
>> >
>> >> -    int rc = -1;
>> >> -    struct nlmsgerr *err;
>> >> -    struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
>> >>  int ifindex;
>> >> -    unsigned int recvbuflen;
>> >> -    struct nl_msg *nl_msg;
>> >> -    struct nlattr *linkinfo, *info_data;
>> >> -    char macstr[VIR_MAC_STRING_BUFLEN];
>> >> -    VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
>> >> -
>> >> -    if (virNetDevGetIndex(srcdev, ) < 0)
>> 

Re: [libvirt] [PATCH] Add virNetlinkNewLink for simplifying virNetDev*Create

2018-08-31 Thread Erik Skultety
On Thu, Aug 30, 2018 at 02:27:05PM +0800, Shi Lei wrote:
> Thanks for your comments.
> But I have several questions, please see below...
>
> On 2018-08-29 at 19:43, Erik Skultety wrote:
> >On Thu, Aug 23, 2018 at 12:15:08PM +0800, Shi Lei wrote:
> >> This patch adds virNetlinkNewLink for simplifying virNetDevMacVLanCreate
> >> and virNetDevBridgeCreate.
> >>
> >> Signed-off-by: Shi Lei 
> >> ---
> >
> >There are multiple changes happening in this patch so it will need to be 
> >split
> >into several patches, see below...
>
> Okay. Then the v2 series should be like:
> [patch v2 0/4]:  ... cover ...
> [patch v2 1/4]:  Add wrapper macros to make code more readable
> [patch v2 2/4]:  Introduce virNetlinkNewLink

2/4 would come before 1/4

> [patch v2 3/4]:  Replace the implementation of virNetDevBridgeCreate
> [patch v2 4/4]:  Replace the implementation of virNetDevMacVLanCreate

3/4 + 4/4 would be a single patch

...

> >> +static int
> >> +virNetDevMacVLanCreateCallback(struct nl_msg *nl_msg, const void *opaque)
> >> +{
> >> +    const uint32_t *mode = (const uint32_t *) opaque;
> >> +    if (!nl_msg || !opaque) {
> >> +    virReportError(VIR_ERR_INTERNAL_ERROR,
> >> +   _("nl_msg %p or opaque %p is NULL"),
> >> +   nl_msg, opaque);
> >> +    return -1;
> >> +    }
> >> +
> >> +    if (*mode > 0) {
> >> +    struct nlattr *info_data;
> >> +    if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
> >> +    goto buffer_too_small;
> >> +
> >> +    if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(*mode), mode) < 0)
> >> +    goto buffer_too_small;
> >> +
> >> +    nla_nest_end(nl_msg, info_data);
> >> +    }
> >> +
> >> +    return 0;
> >> +
> >> + buffer_too_small:
> >> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> >> +   _("allocated netlink buffer is too small"));
> >> +    return -1;
> >> +}
> >
> >Having a callback just to add a nested data into nl_msg doesn't feel like the
> >right approach, I'd expect a callback to do more specific stuff, this should 
> >be
> >special-cased in virNetlinkNewLink.
>
> I looked through the code for ip-link in iproute2 which could be a good 
> example
> for netlink. And I found that the differences of attributes of various 
> net-devices are
> confined to IFLA_INFO_DATA or IFLA_INFO_SLAVE_DATA(this is not used in 
> libvirt).
> The code fragment in iplink.c:
>
>         if (ulinep && !strcmp(ulinep, "_slave")) {
>             ... ...
>             lu = get_link_slave_kind(slavebuf);
>             iflatype = IFLA_INFO_SLAVE_DATA;
>         } else {
> =>       lu = get_link_kind(type);             /* Get pointer to the driver 
> for this type */
> =>       iflatype = IFLA_INFO_DATA;       /* NEST will be for IFLA_INFO_DATA 
> */
>         }
>         if (lu && argc) {
> =>       struct rtattr *data = addattr_nest(, sizeof(req), iflatype);   
>  /* NEST BEGIN */
>
>             
>             if (lu->parse_opt &&
>                 lu->parse_opt(lu, argc, argv, ))
>                 return -1;
>             
>             ^The lu points to various types of net-drivers(e.g. 
> macvlan/bridge/vxlan/vlan ...)
>                which pack all special self-attributes in their parse_opt 
> callback
>
> =>        addattr_nest_end(, data);    /* NEST END */
>
> So I think that it's reasonable for us to have a callback to handle it just 
> as iproute2
> since iproute2 could almost create all the types of net-devices.

I went through the iproute2 code and it completely makes sense for them to
utilize callbacks here, given the amount of driver-specific options each of the
device type has. While I agree that we could make use of this in libvirt one
day, I don't feel like we need to do it now, since I don't think it brings
any noticeable benefit in its currently proposed form + as I already mentioned,
we can switch to this scheme once there are more than 1 netlink types which
could make use of it.

>
> >
> >> +
> >> +
> >>  /**
> >>   * virNetDevMacVLanCreate:
> >>   *
> >> @@ -307,113 +338,29 @@ virNetDevMacVLanCreate(const char *ifname,
> >> uint32_t macvlan_mode,
> >> int *retry)
> >>  {
> >
> >^This replacement would be the last patch in the series.
>
> Okay.
>
> >
> >> -    int rc = -1;
> >> -    struct nlmsgerr *err;
> >> -    struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
> >>  int ifindex;
> >> -    unsigned int recvbuflen;
> >> -    struct nl_msg *nl_msg;
> >> -    struct nlattr *linkinfo, *info_data;
> >> -    char macstr[VIR_MAC_STRING_BUFLEN];
> >> -    VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
> >> -
> >> -    if (virNetDevGetIndex(srcdev, ) < 0)
> >> -    return -1;
> >> -
> >> +    int error = 0;
> >>  *retry = 0;
> >>
> >> -    nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
> >> -    NLM_F_REQUEST | NLM_F_CREATE | 
> >> 

Re: [libvirt] [PATCH] Add virNetlinkNewLink for simplifying virNetDev*Create

2018-08-30 Thread Shi Lei
Thanks for your comments.
But I have several questions, please see below...

On 2018-08-29 at 19:43, Erik Skultety wrote:
>On Thu, Aug 23, 2018 at 12:15:08PM +0800, Shi Lei wrote:
>> This patch adds virNetlinkNewLink for simplifying virNetDevMacVLanCreate
>> and virNetDevBridgeCreate.
>>
>> Signed-off-by: Shi Lei 
>> ---
>
>There are multiple changes happening in this patch so it will need to be split
>into several patches, see below... 

Okay. Then the v2 series should be like:
[patch v2 0/4]:  ... cover ...
[patch v2 1/4]:  Add wrapper macros to make code more readable
[patch v2 2/4]:  Introduce virNetlinkNewLink
[patch v2 3/4]:  Replace the implementation of virNetDevBridgeCreate
[patch v2 4/4]:  Replace the implementation of virNetDevMacVLanCreate

>
>>  src/libvirt_private.syms    |   1 +
>>  src/util/virnetdevbridge.c  |  73 +++
>>  src/util/virnetdevmacvlan.c | 137 
>>++--
>>  src/util/virnetlink.c   | 104 +
>>  src/util/virnetlink.h   |   8 +++
>>  5 files changed, 164 insertions(+), 159 deletions(-)
>>
>> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
>> index 47ea35f..23931ba 100644
>> --- a/src/libvirt_private.syms
>> +++ b/src/libvirt_private.syms
>> @@ -2439,6 +2439,7 @@ virNetlinkEventServiceStop;
>>  virNetlinkEventServiceStopAll;
>>  virNetlinkGetErrorCode;
>>  virNetlinkGetNeighbor;
>> +virNetlinkNewLink;
>>  virNetlinkShutdown;
>>  virNetlinkStartup;
>>
>> diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
>> index bc377b5..1f5b37e 100644
>> --- a/src/util/virnetdevbridge.c
>> +++ b/src/util/virnetdevbridge.c
>> @@ -417,77 +417,22 @@ virNetDevBridgeCreate(const char *brname)
>>  {
>>  /* use a netlink RTM_NEWLINK message to create the bridge */
>>  const char *type = "bridge";
>> -    struct nlmsgerr *err;
>> -    struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
>> -    unsigned int recvbuflen;
>> -    struct nlattr *linkinfo;
>> -    VIR_AUTOPTR(virNetlinkMsg) nl_msg = NULL;
>> -    VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
>> +    int error = 0;
>>
>> -    nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
>> -    NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
>> -    if (!nl_msg) {
>> -    virReportOOMError();
>> -    return -1;
>> -    }
>> -
>> -    if (nlmsg_append(nl_msg,  , sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
>> -    goto buffer_too_small;
>> -    if (nla_put(nl_msg, IFLA_IFNAME, strlen(brname)+1, brname) < 0)
>> -    goto buffer_too_small;
>> -    if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
>> -    goto buffer_too_small;
>> -    if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
>> -    goto buffer_too_small;
>> -    nla_nest_end(nl_msg, linkinfo);
>> -
>> -    if (virNetlinkCommand(nl_msg, , , 0, 0,
>> -  NETLINK_ROUTE, 0) < 0) {
>> -    return -1;
>> -    }
>> -
>> -    if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
>> -    goto malformed_resp;
>> -
>> -    switch (resp->nlmsg_type) {
>> -    case NLMSG_ERROR:
>> -    err = (struct nlmsgerr *)NLMSG_DATA(resp);
>> -    if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
>> -    goto malformed_resp;
>> -
>> -    if (err->error < 0) {
>> +    if (virNetlinkNewLink(NULL, brname, NULL, type, NULL, NULL, ) < 
>> 0) {
>>  # if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
>> -    if (err->error == -EOPNOTSUPP) {
>> -    /* fallback to ioctl if netlink doesn't support creating
>> - * bridges
>> - */
>> -    return virNetDevBridgeCreateWithIoctl(brname);
>> -    }
>> -# endif
>> -
>> -    virReportSystemError(-err->error,
>> - _("error creating bridge interface %s"),
>> - brname);
>> -    return -1;
>> +    if (error == -EOPNOTSUPP) {
>> +    /* fallback to ioctl if netlink doesn't support creating 
>> bridges */
>> +    return virNetDevBridgeCreateWithIoctl(brname);
>>  }
>> -    break;
>> +# endif
>> +    virReportSystemError(-error, _("error creating bridge interface 
>> %s"),
>> + brname);
>>
>> -    case NLMSG_DONE:
>> -    break;
>> -    default:
>> -    goto malformed_resp;
>> +    return -1;
>>  }
>>
>>  return 0;
>> -
>> - malformed_resp:
>> -    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> -   _("malformed netlink response message"));
>> -    return -1;
>> - buffer_too_small:
>> -    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> -   _("allocated netlink buffer is too small"));
>> -    return -1;
>>  }
>>
>>
>> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
>> index 2035b1f..1629add 100644
>> --- a/src/util/virnetdevmacvlan.c
>> +++ b/src/util/virnetdevmacvlan.c
>> @@ 

Re: [libvirt] [PATCH] Add virNetlinkNewLink for simplifying virNetDev*Create

2018-08-29 Thread Erik Skultety
On Thu, Aug 23, 2018 at 12:15:08PM +0800, Shi Lei wrote:
> This patch adds virNetlinkNewLink for simplifying virNetDevMacVLanCreate
> and virNetDevBridgeCreate.
>
> Signed-off-by: Shi Lei 
> ---

There are multiple changes happening in this patch so it will need to be split
into several patches, see below...

>  src/libvirt_private.syms|   1 +
>  src/util/virnetdevbridge.c  |  73 +++
>  src/util/virnetdevmacvlan.c | 137 
> ++--
>  src/util/virnetlink.c   | 104 +
>  src/util/virnetlink.h   |   8 +++
>  5 files changed, 164 insertions(+), 159 deletions(-)
>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 47ea35f..23931ba 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2439,6 +2439,7 @@ virNetlinkEventServiceStop;
>  virNetlinkEventServiceStopAll;
>  virNetlinkGetErrorCode;
>  virNetlinkGetNeighbor;
> +virNetlinkNewLink;
>  virNetlinkShutdown;
>  virNetlinkStartup;
>
> diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
> index bc377b5..1f5b37e 100644
> --- a/src/util/virnetdevbridge.c
> +++ b/src/util/virnetdevbridge.c
> @@ -417,77 +417,22 @@ virNetDevBridgeCreate(const char *brname)
>  {
>  /* use a netlink RTM_NEWLINK message to create the bridge */
>  const char *type = "bridge";
> -struct nlmsgerr *err;
> -struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
> -unsigned int recvbuflen;
> -struct nlattr *linkinfo;
> -VIR_AUTOPTR(virNetlinkMsg) nl_msg = NULL;
> -VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
> +int error = 0;
>
> -nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
> -NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
> -if (!nl_msg) {
> -virReportOOMError();
> -return -1;
> -}
> -
> -if (nlmsg_append(nl_msg,  , sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
> -goto buffer_too_small;
> -if (nla_put(nl_msg, IFLA_IFNAME, strlen(brname)+1, brname) < 0)
> -goto buffer_too_small;
> -if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
> -goto buffer_too_small;
> -if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
> -goto buffer_too_small;
> -nla_nest_end(nl_msg, linkinfo);
> -
> -if (virNetlinkCommand(nl_msg, , , 0, 0,
> -  NETLINK_ROUTE, 0) < 0) {
> -return -1;
> -}
> -
> -if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
> -goto malformed_resp;
> -
> -switch (resp->nlmsg_type) {
> -case NLMSG_ERROR:
> -err = (struct nlmsgerr *)NLMSG_DATA(resp);
> -if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
> -goto malformed_resp;
> -
> -if (err->error < 0) {
> +if (virNetlinkNewLink(NULL, brname, NULL, type, NULL, NULL, ) < 0) 
> {
>  # if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
> -if (err->error == -EOPNOTSUPP) {
> -/* fallback to ioctl if netlink doesn't support creating
> - * bridges
> - */
> -return virNetDevBridgeCreateWithIoctl(brname);
> -}
> -# endif
> -
> -virReportSystemError(-err->error,
> - _("error creating bridge interface %s"),
> - brname);
> -return -1;
> +if (error == -EOPNOTSUPP) {
> +/* fallback to ioctl if netlink doesn't support creating bridges 
> */
> +return virNetDevBridgeCreateWithIoctl(brname);
>  }
> -break;
> +# endif
> +virReportSystemError(-error, _("error creating bridge interface %s"),
> + brname);
>
> -case NLMSG_DONE:
> -break;
> -default:
> -goto malformed_resp;
> +return -1;
>  }
>
>  return 0;
> -
> - malformed_resp:
> -virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> -   _("malformed netlink response message"));
> -return -1;
> - buffer_too_small:
> -virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> -   _("allocated netlink buffer is too small"));
> -return -1;
>  }
>
>
> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
> index 2035b1f..1629add 100644
> --- a/src/util/virnetdevmacvlan.c
> +++ b/src/util/virnetdevmacvlan.c
> @@ -283,6 +283,37 @@ virNetDevMacVLanReleaseName(const char *name)
>  }
>
>
> +static int
> +virNetDevMacVLanCreateCallback(struct nl_msg *nl_msg, const void *opaque)
> +{
> +const uint32_t *mode = (const uint32_t *) opaque;
> +if (!nl_msg || !opaque) {
> +virReportError(VIR_ERR_INTERNAL_ERROR,
> +   _("nl_msg %p or opaque %p is NULL"),
> +   nl_msg, opaque);
> +return -1;
> +}
> +
> +if (*mode > 0) {
> +struct nlattr *info_data;
> +if (!(info_data = nla_nest_start(nl_msg, 

[libvirt] [PATCH] Add virNetlinkNewLink for simplifying virNetDev*Create

2018-08-22 Thread Shi Lei
This patch adds virNetlinkNewLink for simplifying virNetDevMacVLanCreate
and virNetDevBridgeCreate.

Signed-off-by: Shi Lei 
---
 src/libvirt_private.syms|   1 +
 src/util/virnetdevbridge.c  |  73 +++
 src/util/virnetdevmacvlan.c | 137 ++--
 src/util/virnetlink.c   | 104 +
 src/util/virnetlink.h   |   8 +++
 5 files changed, 164 insertions(+), 159 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 47ea35f..23931ba 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2439,6 +2439,7 @@ virNetlinkEventServiceStop;
 virNetlinkEventServiceStopAll;
 virNetlinkGetErrorCode;
 virNetlinkGetNeighbor;
+virNetlinkNewLink;
 virNetlinkShutdown;
 virNetlinkStartup;
 
diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
index bc377b5..1f5b37e 100644
--- a/src/util/virnetdevbridge.c
+++ b/src/util/virnetdevbridge.c
@@ -417,77 +417,22 @@ virNetDevBridgeCreate(const char *brname)
 {
 /* use a netlink RTM_NEWLINK message to create the bridge */
 const char *type = "bridge";
-struct nlmsgerr *err;
-struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
-unsigned int recvbuflen;
-struct nlattr *linkinfo;
-VIR_AUTOPTR(virNetlinkMsg) nl_msg = NULL;
-VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
+int error = 0;
 
-nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
-NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
-if (!nl_msg) {
-virReportOOMError();
-return -1;
-}
-
-if (nlmsg_append(nl_msg,  , sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
-goto buffer_too_small;
-if (nla_put(nl_msg, IFLA_IFNAME, strlen(brname)+1, brname) < 0)
-goto buffer_too_small;
-if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
-goto buffer_too_small;
-if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
-goto buffer_too_small;
-nla_nest_end(nl_msg, linkinfo);
-
-if (virNetlinkCommand(nl_msg, , , 0, 0,
-  NETLINK_ROUTE, 0) < 0) {
-return -1;
-}
-
-if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
-goto malformed_resp;
-
-switch (resp->nlmsg_type) {
-case NLMSG_ERROR:
-err = (struct nlmsgerr *)NLMSG_DATA(resp);
-if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
-goto malformed_resp;
-
-if (err->error < 0) {
+if (virNetlinkNewLink(NULL, brname, NULL, type, NULL, NULL, ) < 0) {
 # if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
-if (err->error == -EOPNOTSUPP) {
-/* fallback to ioctl if netlink doesn't support creating
- * bridges
- */
-return virNetDevBridgeCreateWithIoctl(brname);
-}
-# endif
-
-virReportSystemError(-err->error,
- _("error creating bridge interface %s"),
- brname);
-return -1;
+if (error == -EOPNOTSUPP) {
+/* fallback to ioctl if netlink doesn't support creating bridges */
+return virNetDevBridgeCreateWithIoctl(brname);
 }
-break;
+# endif
+virReportSystemError(-error, _("error creating bridge interface %s"),
+ brname);
 
-case NLMSG_DONE:
-break;
-default:
-goto malformed_resp;
+return -1;
 }
 
 return 0;
-
- malformed_resp:
-virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-   _("malformed netlink response message"));
-return -1;
- buffer_too_small:
-virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-   _("allocated netlink buffer is too small"));
-return -1;
 }
 
 
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 2035b1f..1629add 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -283,6 +283,37 @@ virNetDevMacVLanReleaseName(const char *name)
 }
 
 
+static int
+virNetDevMacVLanCreateCallback(struct nl_msg *nl_msg, const void *opaque)
+{
+const uint32_t *mode = (const uint32_t *) opaque;
+if (!nl_msg || !opaque) {
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("nl_msg %p or opaque %p is NULL"),
+   nl_msg, opaque);
+return -1;
+}
+
+if (*mode > 0) {
+struct nlattr *info_data;
+if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
+goto buffer_too_small;
+
+if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(*mode), mode) < 0)
+goto buffer_too_small;
+
+nla_nest_end(nl_msg, info_data);
+}
+
+return 0;
+
+ buffer_too_small:
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("allocated netlink buffer is too small"));
+return -1;
+}
+
+
 /**
  * virNetDevMacVLanCreate:
  *
@@ -307,113