On 2021-01-06 at 00:00, Michal Privoznik wrote:
On 12/21/20 4: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(a)massclouds.com>
> ---
> src/util/virnetlink.c | 210 +++++++++++++++---------------------------
> src/util/virnetlink.h | 4 +-
> 2 files changed, 78 insertions(+), 136 deletions(-)
Nice cleanup. Patches 1-3 look good.
Okay.
>
> diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c
> index fdcb0dc0..7bea38c0 100644
> --- a/src/util/virnetlink.c
> +++ b/src/util/virnetlink.c
> @@ -353,6 +353,48 @@ int virNetlinkCommand(struct nl_msg *nl_msg,
> return 0;
> }
>
> +
> +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 = (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;
I wonder whether we should report an error here. I mean, if err->error
is set (and not EOPNOTSUPP) then it's stored into *error, good. But -1
is returned ...
> + return -1;
.. here and it's indistinguishable to the caller from -1 returned in
'malformed_resp'. Looking at the usage in next hunks, how about:
if (error)
*error = err->error;
else
virReportSystemError(-err->error, ...);
return -1;
Okay.
> + }
> + }
> +
> + 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 +438,7 @@ virNetlinkDumpCommand(struct nl_msg *nl_msg,
> return 0;
> }
>
> +
> /**
> * virNetlinkDumpLink:
> *
> @@ -420,15 +463,13 @@ 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;
>
> if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname,
&ifindex) < 0)
> return -1;
> @@ -459,46 +500,19 @@ 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, NULL, NULL) < 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) {
> - virReportSystemError(-err->error,
> - _("error dumping %s (%d) interface"),
> - ifname, ifindex);
Here we'd report an error.
Okay.
> - return -1;
> - }
> - break;
> -
> - case GENL_ID_CTRL:
> - case NLMSG_DONE:
> - rc = nlmsg_parse(resp, sizeof(struct ifinfomsg),
> - tb, IFLA_MAX, NULL);
> - if (rc < 0)
> - goto malformed_resp;
> - break;
> -
> - default:
> - goto malformed_resp;
> + if ((resp->nlmsg_type != GENL_ID_CTRL && resp->nlmsg_type !=
NLMSG_DONE) ||
> + nlmsg_parse(resp, sizeof(struct ifinfomsg), tb, IFLA_MAX, NULL) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed netlink response message"));
> + return -1;
> }
>
> *nlData = g_steal_pointer(&resp);
> return 0;
> -
> - malformed_resp:
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("malformed netlink response message"));
> - return rc;
> }
>
>
> @@ -523,13 +537,12 @@ virNetlinkNewLink(const char *ifname,
> virNetlinkNewLinkDataPtr extra_args,
> int *error)
> {
> - struct nlmsgerr *err;
> struct nlattr *linkinfo = NULL;
> struct nlattr *infodata = NULL;
> - unsigned int buflen;
> struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
> g_autoptr(virNetlinkMsg) nl_msg = NULL;
> g_autofree struct nlmsghdr *resp = NULL;
> + unsigned int resp_len = 0;
>
> *error = 0;
>
> @@ -591,37 +604,17 @@ virNetlinkNewLink(const char *ifname,
> }
> }
>
> - if (virNetlinkCommand(nl_msg, &resp, &buflen, 0, 0, NETLINK_ROUTE, 0)
< 0)
> + if (virNetlinkTalk(ifname, nl_msg, 0, 0,
> + &resp, &resp_len, error, NULL) < 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;
But here we wouldn't.
Okay.
> - }
> - break;
> -
> - case NLMSG_DONE:
> - break;
> -
> - default:
> - goto malformed_resp;
> + if (resp->nlmsg_type != NLMSG_DONE) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed netlink response message"));
> + return -1;
> }
>
> return 0;
> -
> - malformed_resp:
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("malformed netlink response message"));
> - return -1;
> }
>
>
> @@ -641,13 +634,12 @@ virNetlinkNewLink(const char *ifname,
> * Returns 0 on success, -1 on fatal error.
> */
> int
> -virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback)
> +virNetlinkDelLink(const char *ifname, virNetlinkTalkFallback fallback)
> {
> - struct nlmsgerr *err;
> struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
> - unsigned int recvbuflen;
> g_autoptr(virNetlinkMsg) nl_msg = NULL;
> g_autofree struct nlmsghdr *resp = NULL;
> + unsigned int resp_len = 0;
>
> nl_msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
> if (!nl_msg) {
> @@ -659,44 +651,17 @@ virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback
fallback)
>
> NETLINK_MSG_PUT(nl_msg, IFLA_IFNAME, (strlen(ifname) + 1), ifname);
>
> - if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
> - NETLINK_ROUTE, 0) < 0) {
> + if (virNetlinkTalk(ifname, nl_msg, 0, 0,
> + &resp, &resp_len, NULL, fallback) < 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 == EOPNOTSUPP && fallback)
> - return fallback(ifname);
> -
> - if (err->error) {
> - virReportSystemError(-err->error,
> - _("error destroying network device %s"),
> - ifname);
And here we would report an error again.
Okay.
> - return -1;
> - }
> - break;
> -
> - case NLMSG_DONE:
> - break;
> -
> - default:
> - goto malformed_resp;
> + if (resp->nlmsg_type != NLMSG_DONE) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed netlink response message"));
> + return -1;
> }
>
> return 0;
> -
> - malformed_resp:
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("malformed netlink response message"));
> - return -1;
> }
>
> /**
> @@ -712,18 +677,17 @@ virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback
fallback)
> *
> * Get neighbor table entry from netlink.
> *
> - * Returns 0 on success, -1 on fatal error.
> + * Returns length of the raw data from netlink on success, -1 on fatal error.
> */
> int
> virNetlinkGetNeighbor(void **nlData, uint32_t src_pid, uint32_t dst_pid)
> {
> - struct nlmsgerr *err;
> struct ndmsg ndinfo = {
> .ndm_family = AF_UNSPEC,
> };
> - unsigned int recvbuflen;
> g_autoptr(virNetlinkMsg) nl_msg = NULL;
> g_autofree struct nlmsghdr *resp = NULL;
> + unsigned int resp_len = 0;
>
> nl_msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_DUMP | NLM_F_REQUEST);
> if (!nl_msg) {
> @@ -733,40 +697,18 @@ virNetlinkGetNeighbor(void **nlData, uint32_t src_pid, uint32_t
dst_pid)
>
> NETLINK_MSG_APPEND(nl_msg, sizeof(ndinfo), &ndinfo);
>
> - if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
> - src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
> + if (virNetlinkTalk(NULL, nl_msg, src_pid, dst_pid,
> + &resp, &resp_len, NULL, NULL) < 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) {
> - virReportSystemError(-err->error,
> - "%s", _("error dumping"));
> - return -1;
Ditto.
Okay.
> - }
> - break;
> -
> - case RTM_NEWNEIGH:
> - break;
> -
> - default:
> - goto malformed_resp;
> + if (resp->nlmsg_type != RTM_NEWNEIGH) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed netlink response message"));
> + return -1;
> }
>
> *nlData = g_steal_pointer(&resp);
> - return recvbuflen;
> -
> - malformed_resp:
> - virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> - _("malformed netlink response message"));
> - return -1;
> + return resp_len;
> }
>
Michal
Thanks!
Shi Lei