[libvirt] [PATCHv2 1/4] Introduce virNetlinkNewLink

Shi Lei shi_lei at massclouds.com
Thu Sep 6 04:21:02 UTC 2018


On 2018-09-05 at 21:26, Erik Skultety wrote:
>On Wed, Sep 05, 2018 at 04:36:27PM +0800, Shi Lei wrote:
>
>the subject should read:
>
>util: netlink: Introduce virNetlinkNewLink helper
>
>> This patch introduces virNetlinkNewLink which wraps newlink code
>> using libnl.
>
>... virNetlinkNewLink helper which wraps the common libnl/netlink code to
>create a new link. 

Okay.

>
>>
>> Signed-off-by: Shi Lei <shi_lei at massclouds.com>
>> ---
>>  src/libvirt_private.syms |   1 +
>>  src/util/virnetlink.c    | 120 +++++++++++++++++++++++++++++++++++++--
>>  src/util/virnetlink.h    |  13 +++++
>>  3 files changed, 129 insertions(+), 5 deletions(-)
>>
>> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
>> index e2340d2..77c9b9e 100644
>> --- a/src/libvirt_private.syms
>> +++ b/src/libvirt_private.syms
>> @@ -2447,6 +2447,7 @@ virNetlinkEventServiceStop;
>>  virNetlinkEventServiceStopAll;
>>  virNetlinkGetErrorCode;
>>  virNetlinkGetNeighbor;
>> +virNetlinkNewLink;
>>  virNetlinkShutdown;
>>  virNetlinkStartup;
>>
>> diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c
>> index 8f06446..32aa62d 100644
>> --- a/src/util/virnetlink.c
>> +++ b/src/util/virnetlink.c
>> @@ -420,10 +420,8 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
>>      if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
>>          goto buffer_too_small;
>>
>> -    if (ifname) {
>> -        if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
>> -            goto buffer_too_small;
>> -    }
>> +    if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0)
>> +        goto buffer_too_small;
>
>unrelated to this patch...this kind of change should be a separate patch
>somewhere at the beginning of the series... 

Okay.

>
>>
>>  # ifdef RTEXT_FILTER_VF
>>      /* if this filter exists in the kernel's netlink implementation,
>> @@ -488,6 +486,118 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
>>  }
>>
>>
>> +/**
>> + * virNetlinkNewLink:
>> + *
>> + * @ifname: Name of the link
>> + * @type: The type of device, i.e., "bridge", "macvtap", "macvlan"
>
>s/Name/name
>s/The/the
>s/of device/of the device/
>s/i.e.,/i.e. 

Okay.

>
>> + * @ifindex: The index for the 'link' device
>
>I think ^this one should be part of the extra args, e.g. bridge doesn't use it 

Okay.

>
>> + * @data: The extra args for creating the netlink interface
>
>actually extra_args is a better name for the argument :) 

Yes. The extra_args is more clear.

>
>> + * @error: for retrieving error code
>
>s/for retrieving error code/netlink error code 

Okay.

>
>> + *
>> + * Create a network "link" (aka interface aka device) with the given
>> + * args. This works for many different types of network devices,
>> + * including macvtap and bridges.
>
>A generic wrapper to create a network link. 

Okay.

>
>> + *
>> + * Returns 0 on success, -1 on fatal error.
>> + */
>> +int
>> +virNetlinkNewLink(const char *ifname,
>> +                  const char *type,
>> +                  const int *ifindex,
>> +                  virNetlinkNewLinkDataPtr data,
>> +                  int *error)
>> +{
>> +    struct nlmsgerr *err;
>> +    struct nlattr *linkinfo = NULL;
>> +    struct nlattr *infodata = NULL;
>> +    unsigned int buflen;
>> +    struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
>> +    VIR_AUTOPTR(virNetlinkMsg) nl_msg = NULL;
>> +    VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
>> +
>> +    *error = 0;
>> +
>> +    if (!data)
>> +        return -1;
>
>Extra args should not be required, BridgeCreate doesn't make use of them. That
>said, I think it's reasonable to make @ifname and @type mandatory and fail
>whenever we don't get either of them:
>
>if (!ifname && !type)
>    virReportError(...); 

Okay. I see.

>
>> +
>> +    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,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
>> +        goto buffer_too_small;
>> +
>> +    if (ifindex && nla_put_u32(nl_msg, IFLA_LINK, *ifindex) < 0)
>> +        goto buffer_too_small;
>> +
>> +    if (data->mac && nla_put(nl_msg, IFLA_ADDRESS, VIR_MAC_BUFLEN, data->mac) < 0)
>> +        goto buffer_too_small;
>
>The order of the data in the msg payload doesn't matter, right? If that's true,
>we could move everything related to @extra_args and *not* related to nested
>containers right before actually calling into virNetlinkCommand. If the order
>does actually matter, then you can disregard this comment. 

Right. I look through the rtnl_newlink function which uses nlmsg_parse which uses nla_parse.
In nla_parse function, we can see that the order of the netlink attributes does *not* matter.
So I could do as you said.

>
>> +
>> +    if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0)
>> +        goto buffer_too_small;
>> +
>> +    if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
>> +        goto buffer_too_small;
>> +
>> +    if (type && nla_put_string(nl_msg, IFLA_INFO_KIND, type) < 0)
>> +        goto buffer_too_small;
>> +
>> +    if ((STREQ(type, "macvtap") || STREQ(type, "macvlan")) &&
>> +        data->macvlan_mode && *data->macvlan_mode > 0) {
>
>this check would get a bit uglier though:
>if ((STREQ(type, "macvtap") || STREQ(type, "macvlan")) &&
>     extra_args &&
>     extra_args->macvlan_mode &&
>     *extra_args->macvlan_mode > 0) 

Okay.

>
>> +        if (!(infodata = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
>> +            goto buffer_too_small;
>> +
>> +        if (nla_put_u32(nl_msg, IFLA_MACVLAN_MODE, *data->macvlan_mode) < 0)
>> +            goto buffer_too_small;
>> +
>> +        nla_nest_end(nl_msg, infodata);
>> +    }
>> +
>> +    nla_nest_end(nl_msg, linkinfo);
>
>here you'd have:
>
>if (extra_args) {
>...
>} 

Okay. I see.

>
>> +
>> +    if (virNetlinkCommand(nl_msg, &resp, &buflen, 0, 0, NETLINK_ROUTE, 0) < 0)
>> +        return -1;
>> +
>> +    if (buflen < 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) {
>> +            *error = err->error;
>> +            return -1;
>> +        }
>> +        break;
>> +
>> +    case NLMSG_DONE:
>> +        break;
>> +
>> +    default:
>> +        goto malformed_resp;
>> +    }
>> +
>> +    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;
>> +}
>> +
>> +
>>  /**
>>   * virNetlinkDelLink:
>>   *
>> @@ -522,7 +632,7 @@ virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback)
>>      if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
>>          goto buffer_too_small;
>>
>> -    if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
>> +    if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0)
>>          goto buffer_too_small;
>
>...unrelated to this patch... 

Okay.

>
>>
>>      if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
>> diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h
>> index 1e1e616..8163a81 100644
>> --- a/src/util/virnetlink.h
>> +++ b/src/util/virnetlink.h
>> @@ -65,6 +65,19 @@ int virNetlinkDumpCommand(struct nl_msg *nl_msg,
>>                            unsigned int protocol, unsigned int groups,
>>                            void *opaque);
>>
>> +typedef struct _virNetlinkNewLinkData virNetlinkNewLinkData;
>> +typedef virNetlinkNewLinkData *virNetlinkNewLinkDataPtr;
>> +struct _virNetlinkNewLinkData {
>> +    const virMacAddr *mac;          /* The MAC address of the device */
>> +    const uint32_t *macvlan_mode;   /* The mode of macvlan */
>
>this would contain const int *ifindex too... 

Okay.

>
>> +};
>> +
>> +int virNetlinkNewLink(const char *ifname,
>> +                      const char *type,
>> +                      const int *ifindex,
>> +                      virNetlinkNewLinkDataPtr data,
>> +                      int *error);
>> +
>>  typedef int (*virNetlinkDelLinkFallback)(const char *ifname);
>>
>>  int virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback);
>
>The patch looks good, except for the few nitpicks I mentioned.
>
>Erik 

Thanks for your comments!

Shi Lei




More information about the libvir-list mailing list