[PATCHv3 4/4] netlink: Introduce a helper function to simplify netlink functions

Shi Lei shi_lei at massclouds.com
Mon Jan 11 02:23:37 UTC 2021


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;
 }
 
+
+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;
+            else
+                virReportSystemError(-err->error, "%s", _("netlink error"));
+
+            return -1;
+        }
+    }
+
+    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,
+                             _("error dumping %s (%d) interface"),
+                             ifname, ifindex);
         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);
-            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 != NLMSG_ERROR &&
+         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 +550,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 +617,18 @@ 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;
-        }
-        break;
-
-    case NLMSG_DONE:
-        break;
-
-    default:
-        goto malformed_resp;
+    if (resp->nlmsg_type != NLMSG_ERROR &&
+        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 +648,13 @@ 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;
+    int error = 0;
 
     nl_msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
     if (!nl_msg) {
@@ -659,44 +666,22 @@ 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, &error, fallback) < 0) {
+        virReportSystemError(error,
+                             _("error destroying network device %s"),
+                             ifname);
         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);
-            return -1;
-        }
-        break;
-
-    case NLMSG_DONE:
-        break;
-
-    default:
-        goto malformed_resp;
+    if (resp->nlmsg_type != NLMSG_ERROR &&
+        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 +697,18 @@ 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;
+    int error = 0;
 
     nl_msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_DUMP | NLM_F_REQUEST);
     if (!nl_msg) {
@@ -733,40 +718,21 @@ 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, &error, NULL) < 0) {
+        virReportSystemError(error, "%s", _("error dumping"));
         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;
-        }
-        break;
-
-    case RTM_NEWNEIGH:
-        break;
-
-    default:
-        goto malformed_resp;
+    if (resp->nlmsg_type != NLMSG_ERROR &&
+        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;
 }
 
 int
@@ -1300,7 +1266,7 @@ virNetlinkDumpLink(const char *ifname G_GNUC_UNUSED,
 
 int
 virNetlinkDelLink(const char *ifname G_GNUC_UNUSED,
-                  virNetlinkDelLinkFallback fallback G_GNUC_UNUSED)
+                  virNetlinkTalkFallback fallback G_GNUC_UNUSED)
 {
     virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
     return -1;
diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h
index 966d6db3..cab685fe 100644
--- a/src/util/virnetlink.h
+++ b/src/util/virnetlink.h
@@ -69,9 +69,9 @@ int virNetlinkNewLink(const char *ifname,
                       virNetlinkNewLinkDataPtr data,
                       int *error);
 
-typedef int (*virNetlinkDelLinkFallback)(const char *ifname);
+typedef int (*virNetlinkTalkFallback)(const char *ifname);
 
-int virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback);
+int virNetlinkDelLink(const char *ifname, virNetlinkTalkFallback fallback);
 
 int virNetlinkGetErrorCode(struct nlmsghdr *resp, unsigned int recvbuflen);
 
-- 
2.25.1





More information about the libvir-list mailing list