[PATCHv3 4/4] netlink: Introduce a helper function to simplify netlink functions
Shi Lei
shi_lei at massclouds.com
Tue Jan 12 01:29:09 UTC 2021
On 2021-01-11 at 19:26, Michal Privoznik wrote:
>On 1/11/21 3:23 AM, Shi Lei wrote:
>> Extract common code as helper function virNetlinkTalk, then simplify
>> the functions virNetlink[DumpLink|NewLink|DelLink|GetNeighbor].
>>
>> Signed-off-by: Shi Lei <shi_lei at massclouds.com>
>> ---
>> src/util/virnetlink.c | 232 ++++++++++++++++++------------------------
>> src/util/virnetlink.h | 4 +-
>> 2 files changed, 101 insertions(+), 135 deletions(-)
>>
>> diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c
>> index fdcb0dc0..650acff7 100644
>> --- a/src/util/virnetlink.c
>> +++ b/src/util/virnetlink.c
>> @@ -353,6 +353,54 @@ int virNetlinkCommand(struct nl_msg *nl_msg,
>> return 0;
>> }
>>
>> +
>
>I guess we should document that NLMSG_ERROR and err->error == 0 is a
>valid case and no error. How about:
>
>/**
> * virNetlinkTalk:
> * @ifname: name of the link
> * @nl_msg: pointer to netlink message
> * @src_pid: pid used for nl_pid of the local end of the netlink message
> * (0 == "use getpid()")
> * @dst_pid: pid of destination nl_pid if the kernel
> * is not the target of the netlink message but it is to be
> * sent to another process (0 if sending to the kernel)
> * @resp: pointer to pointer where response buffer will be allocated
> * @resp_len: pointer to integer holding the size of the response buffer
> * on return of the function
> * @error: pointer to store netlink error (-errno)
> * @fallback: pointer to an alternate function that will be called in case
> * netlink fails with EOPNOTSUPP (any other error will simply be
> * treated as an error)
> *
> * Simple wrapper around virNetlinkCommand(). The returned netlink message
> * is allocated at @resp. Please note that according to netlink(7) man
>page,
> * reply with type of NLMSG_ERROR and @error == 0 is an acknowledgment and
> * thus not an error.
> *
> * Returns: 0 on success,
> * -1 otherwise (error reported if @error == NULL)
> */
>
>
>> +static int
>> +virNetlinkTalk(const char *ifname,
>> + virNetlinkMsg *nl_msg,
>> + uint32_t src_pid,
>> + uint32_t dst_pid,
>> + struct nlmsghdr **resp,
>> + unsigned int *resp_len,
>> + int *error,
>> + virNetlinkTalkFallback fallback)
>> +{
>> + if (virNetlinkCommand(nl_msg, resp, resp_len,
>> + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
>> + return -1;
>> +
>> + if (*resp_len < NLMSG_LENGTH(0) || *resp == NULL)
>> + goto malformed_resp;
>> +
>> + if ((*resp)->nlmsg_type == NLMSG_ERROR) {
>> + struct nlmsgerr *err;
>> +
>> + err = (struct nlmsgerr *) NLMSG_DATA(*resp);
>> +
>> + if ((*resp)->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
>> + goto malformed_resp;
>> +
>> + if (-err->error == EOPNOTSUPP && fallback)
>> + return fallback(ifname);
>> +
>> + if (err->error < 0) {
>> + if (error)
>> + *error = err->error;
>
>So this sets @error to a negative number. [1]
>
>> + else
>> + virReportSystemError(-err->error, "%s", _("netlink error"));
>> +
>> + return -1;
>> + }
>
>And here I'd put:
>
> /* According to netlink(7) man page NLMSG_ERROR packet with error
> * field set to 0 is an acknowledgment packet and thus not an
>error. */
>
>
>> + }
>> +
>> + return 0;
>> +
>> + malformed_resp:
>> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> + _("malformed netlink response message"));
>> + return -1;
>> +}
>> +
>> +
>> int
>> virNetlinkDumpCommand(struct nl_msg *nl_msg,
>> virNetlinkDumpCallback callback,
>> @@ -396,6 +444,7 @@ virNetlinkDumpCommand(struct nl_msg *nl_msg,
>> return 0;
>> }
>>
>> +
>> /**
>> * virNetlinkDumpLink:
>> *
>> @@ -420,15 +469,14 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
>> void **nlData, struct nlattr **tb,
>> uint32_t src_pid, uint32_t dst_pid)
>> {
>> - int rc = -1;
>> - struct nlmsgerr *err;
>> struct ifinfomsg ifinfo = {
>> .ifi_family = AF_UNSPEC,
>> .ifi_index = ifindex
>> };
>> - unsigned int recvbuflen;
>> g_autoptr(virNetlinkMsg) nl_msg = NULL;
>> g_autofree struct nlmsghdr *resp = NULL;
>> + unsigned int resp_len = 0;
>> + int error = 0;
>>
>> if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0)
>> return -1;
>> @@ -459,46 +507,25 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
>> }
>> # endif
>>
>> - if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
>> - src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
>> + if (virNetlinkTalk(ifname, nl_msg, src_pid, dst_pid,
>> + &resp, &resp_len, &error, NULL) < 0) {
>> + virReportSystemError(error,
>
>1: and here it is used as if it was positive. We need -error. And in the
>rest of places too.
>
>Anyway, I can fix that before pushing, so that you don't have to send
>another version. Do you agree if this is squashed in?
>
>diff --git c/src/util/virnetlink.c w/src/util/virnetlink.c
>index 650acff7d7..9bd7339054 100644
>--- c/src/util/virnetlink.c
>+++ w/src/util/virnetlink.c
>@@ -354,6 +354,31 @@ int virNetlinkCommand(struct nl_msg *nl_msg,
> }
>
>
>+/**
>+ * virNetlinkTalk:
>+ * @ifname: name of the link
>+ * @nl_msg: pointer to netlink message
>+ * @src_pid: pid used for nl_pid of the local end of the netlink message
>+ * (0 == "use getpid()")
>+ * @dst_pid: pid of destination nl_pid if the kernel
>+ * is not the target of the netlink message but it is to be
>+ * sent to another process (0 if sending to the kernel)
>+ * @resp: pointer to pointer where response buffer will be allocated
>+ * @resp_len: pointer to integer holding the size of the response buffer
>+ * on return of the function
>+ * @error: pointer to store netlink error (-errno)
>+ * @fallback: pointer to an alternate function that will be called in case
>+ * netlink fails with EOPNOTSUPP (any other error will simply be
>+ * treated as an error)
>+ *
>+ * Simple wrapper around virNetlinkCommand(). The returned netlink message
>+ * is allocated at @resp. Please note that according to netlink(7) man
>page,
>+ * reply with type of NLMSG_ERROR and @error == 0 is an acknowledgment and
>+ * thus not an error.
>+ *
>+ * Returns: 0 on success,
>+ * -1 otherwise (error reported if @error == NULL)
>+ */
> static int
> virNetlinkTalk(const char *ifname,
> virNetlinkMsg *nl_msg,
>@@ -390,6 +415,9 @@ virNetlinkTalk(const char *ifname,
>
> return -1;
> }
>+
>+ /* According to netlink(7) man page NLMSG_ERROR packet with error
>+ * field set to 0 is an acknowledgment packet and thus not an
>error. */
> }
>
> return 0;
>@@ -509,7 +537,7 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
>
> if (virNetlinkTalk(ifname, nl_msg, src_pid, dst_pid,
> &resp, &resp_len, &error, NULL) < 0) {
>- virReportSystemError(error,
>+ virReportSystemError(-error,
> _("error dumping %s (%d) interface"),
> ifname, ifindex);
> return -1;
>@@ -668,7 +696,7 @@ virNetlinkDelLink(const char *ifname,
>virNetlinkTalkFallback fallback)
>
> if (virNetlinkTalk(ifname, nl_msg, 0, 0,
> &resp, &resp_len, &error, fallback) < 0) {
>- virReportSystemError(error,
>+ virReportSystemError(-error,
> _("error destroying network device %s"),
> ifname);
> return -1;
>@@ -720,7 +748,7 @@ virNetlinkGetNeighbor(void **nlData, uint32_t
>src_pid, uint32_t dst_pid)
>
> if (virNetlinkTalk(NULL, nl_msg, src_pid, dst_pid,
> &resp, &resp_len, &error, NULL) < 0) {
>- virReportSystemError(error, "%s", _("error dumping"));
>+ virReportSystemError(-error, "%s", _("error dumping neighbor
>table"));
> return -1;
> }
>
>
>
>Michal
>
I agree. Thanks!
Shi Lei
More information about the libvir-list
mailing list