From: Tony Krowiak <akrowiak(a)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(a)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