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. > > Signed-off-by: Shi Lei <shi_lei@xxxxxxxxxxxxxx> > --- > 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... > > # 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. > + * @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 > + * @data: The extra args for creating the netlink interface actually extra_args is a better name for the argument :) > + * @error: for retrieving error code s/for retrieving error code/netlink error code > + * > + * 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. > + * > + * 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(...); > + > + 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. > + > + 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) > + 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) { ... } > + > + 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... > > 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... > +}; > + > +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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list