From: Tony Krowiak <akrowiak@xxxxxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list