[libvirt] [PATCH 1/2] util: Functions for getting/setting device options

akrowiak at linux.vnet.ibm.com akrowiak at linux.vnet.ibm.com
Mon Jan 19 16:18:07 UTC 2015


From: Tony Krowiak <akrowiak at linux.vnet.ibm.com>

This patch provides the utility functions needed to synchronize
the rxfilter changes made to a guest domain with the corresponding
macvtap devices on the host:

* Get/set PROMISC flag
* Get/set ALLMULTI, MULTICAST

Signed-off-by: Tony Krowiak <akrowiak at linux.vnet.ibm.com>
---
 src/libvirt_private.syms |    6 +
 src/util/virnetdev.c     |  346 ++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virnetdev.h     |   14 ++
 3 files changed, 366 insertions(+), 0 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a2eec83..6b49b08 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1646,6 +1646,9 @@ virNetDevGetVirtualFunctionInfo;
 virNetDevGetVirtualFunctions;
 virNetDevGetVLanID;
 virNetDevIsOnline;
+virNetDevIsPromiscuous;
+virNetDevIsRcvAllMulti;
+virNetDevIsRcvMulti;
 virNetDevIsVirtualFunction;
 virNetDevLinkDump;
 virNetDevReplaceMacAddress;
@@ -1663,6 +1666,9 @@ virNetDevSetMTUFromDevice;
 virNetDevSetName;
 virNetDevSetNamespace;
 virNetDevSetOnline;
+virNetDevSetPromiscuous;
+virNetDevSetRcvAllMulti;
+virNetDevSetRcvMulti;
 virNetDevSetupControl;
 virNetDevValidateConfig;
 
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index ef96b2b..c610f5b 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -2337,6 +2337,333 @@ int virNetDevDelMulti(const char *ifname ATTRIBUTE_UNUSED,
 }
 #endif
 
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetPromiscuous:
+ * @ifname: the interface name
+ * @promiscuous: true for receive all packets, false for do not receive
+ *               all packets
+ *
+ * Function to control if an interface is to receive all
+ * packets (receive all, true) or not (do not receive all, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetPromiscuous(const char *ifname,
+                            bool promiscuous)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+    int ifflags;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    if (promiscuous)
+        ifflags = ifr.ifr_flags | IFF_PROMISC;
+    else
+        ifflags = ifr.ifr_flags & ~IFF_PROMISC;
+
+    if (ifr.ifr_flags != ifflags) {
+        ifr.ifr_flags = ifflags;
+        if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+            virReportSystemError(errno,
+                                 _("Cannot set interface flags on '%s'"),
+                                 ifname);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else
+int virNetDevSetPromiscuous(const char *ifname,
+                            bool promiscuous ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to set device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsPromiscuous:
+ * @ifname: the interface name
+ * @promiscuous: where to store the status
+ *
+ * Function to query if an interface is receiving all packets (true) or
+ * not (false)
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int virNetDevIsPromiscuous(const char *ifname,
+                           bool *promiscuous)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    *promiscuous = (ifr.ifr_flags & IFF_PROMISC) ? true : false;
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else
+int virNetDevIsPromiscuous(const char *ifname ATTRIBUTE_UNUSED,
+                            bool *promiscuous ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to retrieve device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif
+
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetRcvMulti:
+ * @ifname: the interface name
+ * @:receive true for receive multicast packets, false for do not receive
+ *           multicast packets
+ *
+ * Function to control if an interface is to receive multicast
+ * packets in which it is interested (receive, true)
+ * or not (do not receive, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetRcvMulti(const char *ifname,
+                         bool receive)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+    int ifflags;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    if (receive)
+        ifflags = ifr.ifr_flags | IFF_MULTICAST;
+    else
+        ifflags = ifr.ifr_flags & ~IFF_MULTICAST;
+
+    if (ifr.ifr_flags != ifflags) {
+        ifr.ifr_flags = ifflags;
+        if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+            virReportSystemError(errno,
+                                 _("Cannot set interface flags on '%s'"),
+                                 ifname);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else
+int virNetDevSetRcvMulti(const char *ifname,
+                         bool receive ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to set device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif /* defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ) */
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsRcvMulti:
+ * @ifname: the interface name
+ * @receive where to store the status
+ *
+ * Function to query whether an interface is receiving multicast packets (true)
+ * in which it is interested, or not (false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevIsRcvMulti(const char *ifname,
+                        bool *receive)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    *receive = (ifr.ifr_flags & IFF_MULTICAST) ? true : false;
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else
+int virNetDevIsRcvMulti(const char *ifname,
+                        bool *receive ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to retrieve device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif /* defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ) */
+
+#if defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevSetRcvAllMulti:
+ * @ifname: the interface name
+ * @:receive true for receive all packets, false for do not receive all packets
+ *
+ * Function to control if an interface is to receive all multicast
+ * packets (receive, true) or not (do not receive, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevSetRcvAllMulti(const char *ifname,
+                            bool receive)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+    int ifflags;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    if (receive)
+        ifflags = ifr.ifr_flags | IFF_ALLMULTI;
+    else
+        ifflags = ifr.ifr_flags & ~IFF_ALLMULTI;
+
+    if (ifr.ifr_flags != ifflags) {
+        ifr.ifr_flags = ifflags;
+        if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+            virReportSystemError(errno,
+                                 _("Cannot set interface flags on '%s'"),
+                                 ifname);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+
+#else
+
+int virNetDevSetRcvAllMulti(const char *ifname,
+                            bool receive ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to set device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif /*defined(SIOCSIFFLAGS) && defined(HAVE_STRUCT_IFREQ)*/
+
+#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ)
+/**
+ * virNetDevIsRcvAllMulti:
+ * @ifname: the interface name
+ * @:receive where to store the status
+ *
+ * Function to query whether an interface is receiving all multicast
+ * packets (receiving, true) or not (is not receiving, false)
+ *
+ * Returns 0 in case of success or -1 on error.
+ */
+int virNetDevIsRcvAllMulti(const char *ifname,
+                           bool *receive)
+{
+    int fd = -1;
+    int ret = -1;
+    struct ifreq ifr;
+
+    if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot get interface flags on '%s'"),
+                             ifname);
+        goto cleanup;
+    }
+
+    *receive = (ifr.ifr_flags & IFF_ALLMULTI) ? true : false;
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#else
+
+int virNetDevIsRcvAllMulti(const char *ifname,
+                           bool *receive ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s",
+                         _("Unable to retrieve device flags for interfaces "
+                           "on this platform"));
+    return -1;
+}
+#endif
+
 static int virNetDevParseMcast(char *buf, virNetDevMcastEntryPtr mcast)
 {
     int ifindex;
@@ -2549,6 +2876,7 @@ int virNetDevGetRxFilter(const char *ifname,
                          virNetDevRxFilterPtr *filter)
 {
     int ret = -1;
+    bool receive;
     virNetDevRxFilterPtr fil = virNetDevRxFilterNew();
 
     if (!fil)
@@ -2560,6 +2888,24 @@ int virNetDevGetRxFilter(const char *ifname,
     if (virNetDevGetMulticastTable(ifname, fil))
         goto cleanup;
 
+    if (virNetDevIsPromiscuous(ifname, &fil->promiscuous))
+        goto cleanup;
+
+    if (virNetDevIsRcvAllMulti(ifname, &receive))
+        goto cleanup;
+
+    if (receive)
+        fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_ALL;
+    else {
+        if (virNetDevIsRcvMulti(ifname, &receive))
+            goto cleanup;
+
+        if (receive)
+            fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NORMAL;
+        else
+            fil->multicast.mode = VIR_NETDEV_RX_FILTER_MODE_NONE;
+    }
+
     ret = 0;
  cleanup:
     if (ret < 0) {
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index fb7988f..4216957 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -200,4 +200,18 @@ int virNetDevDelMulti(const char *ifname,
                       virMacAddrPtr macaddr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 
+int virNetDevSetPromiscuous(const char *ifname, bool promiscuous)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsPromiscuous(const char *ifname, bool *promiscuous)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevSetRcvMulti(const char *ifname, bool receive)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsRcvMulti(const char *ifname, bool *receive)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevSetRcvAllMulti(const char *ifname, bool receive)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevIsRcvAllMulti(const char *ifname, bool *receive)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 #endif /* __VIR_NETDEV_H__ */
-- 
1.7.1




More information about the libvir-list mailing list