[libvirt] [PATCHv2 1/4] Introduce virNetlinkNewLink

Shi Lei shi_lei at massclouds.com
Wed Sep 5 08:36:27 UTC 2018


This patch introduces virNetlinkNewLink which wraps newlink code
using libnl.

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;
 
 # 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"
+ * @ifindex: The index for the 'link' device
+ * @data: The extra args for creating the netlink interface
+ * @error: for retrieving 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.
+ *
+ * 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;
+
+    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;
+
+    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) {
+        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);
+
+    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;
 
     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 */
+};
+
+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);
-- 
2.17.1





More information about the libvir-list mailing list