:p
atchew
Login
Builds for Linux without libnl is broken since commit 582f0966f9b9e2148d8887d072364e2a91aed000 so make libnl mandatory for Linux. Another option is to fix such builds, but it can bring more problems than benefits. libnl is available on all supported distributions so the only practical situation to lack libnl is that a developer does not have a development package of libnl installed. Enabling builds in such a situation make developers use builds divergent from CI and end-user scenarios, which has some implications. Builds without libnl lack several features such as SR-IOV, bridge/tap, switchdev, macvlan, veth, and vlan. Some part of libvirt may expect these features are readily available on Linux, and the lack of libnl may cause a build failure like one mentioned earlier or runtime errors even harder to debug. Developers will then be forced to debug such bugs and to choose either fixing the build configuration that has no real user or work around the issue by installing the development package. In any case, the bridge/tap configuration is one of the fundamental features and developers are likely to want libnl for it. Save the potential trouble for developers by requiring libnl for Linux and let Meson direct them to install libnl. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> --- Supersedes: <20250307-nl-v1-1-c66fc2bf8703@daynix.com> ("[PATCH] util: Check libnl function availability") --- libvirt.spec.in | 2 - meson.build | 16 +-- meson_options.txt | 1 - src/util/virnetdev.c | 223 +++++++++++++++---------------------- src/util/virnetdevbridge.c | 27 +---- src/util/virnetdevip.c | 230 +++++++++++++++++++-------------------- src/util/virnetdevmacvlan.c | 6 +- src/util/virnetdevveth.c | 35 ------ src/util/virnetdevvportprofile.c | 8 +- src/util/virnetlink.c | 8 +- src/util/virnetlink.h | 4 +- tests/virnetdevtest.c | 8 -- 12 files changed, 222 insertions(+), 346 deletions(-) diff --git a/libvirt.spec.in b/libvirt.spec.in index XXXXXXX..XXXXXXX 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -XXX,XX +XXX,XX @@ export SOURCE_DATE_EPOCH=$(stat --printf='%Y' %{_specdir}/libvirt.spec) -Dlibpcap=enabled \ %{?arg_nbdkit} \ %{?arg_nbdkit_config_default} \ - -Dlibnl=enabled \ -Daudit=enabled \ -Ddtrace=enabled \ -Dfirewalld=enabled \ @@ -XXX,XX +XXX,XX @@ export SOURCE_DATE_EPOCH=$(stat --printf='%Y' %{_specdir}/libvirt.spec) -Dlibiscsi=disabled \ -Dnbdkit=disabled \ -Dnbdkit_config_default=disabled \ - -Dlibnl=disabled \ -Dlibpcap=disabled \ -Dlibssh2=disabled \ -Dlibssh=disabled \ diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ endif conf.set10('USE_NBDKIT_DEFAULT', use_nbdkit_default) libnl_version = '3.0' -if not get_option('libnl').disabled() and host_machine.system() == 'linux' - libnl_dep = dependency('libnl-3.0', version: '>=' + libnl_version, required: get_option('libnl')) - libnl_route_dep = dependency('libnl-route-3.0', version: '>=' + libnl_version, required: get_option('libnl')) - - if libnl_dep.found() and libnl_route_dep.found() - libnl_dep = declare_dependency( - dependencies: [ libnl_dep, libnl_route_dep ], - ) - conf.set('WITH_LIBNL', 1) - endif -elif get_option('libnl').enabled() - error('libnl can be enabled only on linux') +if host_machine.system() == 'linux' + libnl_dep = dependency('libnl-3.0', version: '>=' + libnl_version) + libnl_route_dep = dependency('libnl-route-3.0', version: '>=' + libnl_version) + libnl_dep = declare_dependency(dependencies: [ libnl_dep, libnl_route_dep ]) else libnl_dep = dependency('', required: false) endif diff --git a/meson_options.txt b/meson_options.txt index XXXXXXX..XXXXXXX 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -XXX,XX +XXX,XX @@ option('fuse', type: 'feature', value: 'auto', description: 'fuse support') option('glusterfs', type: 'feature', value: 'auto', description: 'glusterfs support') option('json_c', type: 'feature', value: 'auto', description: 'JSON-C support') option('libiscsi', type: 'feature', value: 'auto', description: 'libiscsi support') -option('libnl', type: 'feature', value: 'auto', description: 'libnl support') option('libpcap', type: 'feature', value: 'auto', description: 'libpcap support') option('libssh', type: 'feature', value: 'auto', description: 'libssh support') option('libssh2', type: 'feature', value: 'auto', description: 'libssh2 support') diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -XXX,XX +XXX,XX @@ int virNetDevGetIndex(const char *ifname G_GNUC_UNUSED, #endif /* ! SIOCGIFINDEX */ -#if defined(WITH_LIBNL) +#if defined(__linux__) /** * virNetDevGetMaster: * @ifname: name of interface we're interested in @@ -XXX,XX +XXX,XX @@ virNetDevGetMaster(const char *ifname, char **master) return 0; } -#elif defined(__linux__) - -/* libnl isn't available, so we can't use netlink. - * Fall back to using sysfs - */ -int -virNetDevGetMaster(const char *ifname, char **master) -{ - g_autofree char *path = NULL; - g_autofree char *canonical = NULL; - - if (virNetDevSysfsFile(&path, ifname, "master") < 0) - return -1; - - if (!(canonical = virFileCanonicalizePath(path))) - return -1; - - *master = g_path_get_basename(canonical); - - VIR_DEBUG("IFLA_MASTER for %s is %s", ifname, *master ? *master : "(none)"); - return 0; -} - #else int @@ -XXX,XX +XXX,XX @@ virNetDevGetMaster(const char *ifname G_GNUC_UNUSED, } -#endif /* defined(WITH_LIBNL) */ +#endif /* defined(__linux__) */ #if __linux__ @@ -XXX,XX +XXX,XX @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname, } -# if defined(WITH_LIBNL) - /** * Determine if the device path specified in devpath is a PCI Device * by resolving the 'subsystem'-link in devpath and looking for @@ -XXX,XX +XXX,XX @@ virNetDevGetPCIDevice(const char *devName) return virPCIDeviceNew(vfPCIAddr); } -# endif /* A wrapper to get content of file from ifname SYSFS_NET_DIR @@ -XXX,XX +XXX,XX @@ virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname, return ret; } -#else /* !__linux__ */ -int -virNetDevGetPhysPortID(const char *ifname G_GNUC_UNUSED, - char **physPortID) -{ - /* this actually should never be called, and is just here to - * satisfy the linker. - */ - *physPortID = NULL; - return 0; -} - -int -virNetDevGetPhysPortName(const char *ifname G_GNUC_UNUSED, - char **physPortName) -{ - /* this actually should never be called, and is just here to - * satisfy the linker. - */ - *physPortName = NULL; - return 0; -} - -int -virNetDevGetVirtualFunctions(const char *pfname G_GNUC_UNUSED, - virPCIVirtualFunctionList **vfs G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get virtual functions on this platform")); - return -1; -} - -int -virNetDevIsVirtualFunction(const char *ifname G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to check virtual function status on this platform")); - return -1; -} - -int -virNetDevGetVirtualFunctionIndex(const char *pfname G_GNUC_UNUSED, - const char *vfname G_GNUC_UNUSED, - int *vf_index G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get virtual function index on this platform")); - return -1; -} - -int -virNetDevGetPhysicalFunction(const char *ifname G_GNUC_UNUSED, - char **pfname G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get physical function status on this platform")); - return -1; -} - -int -virNetDevPFGetVF(const char *pfname G_GNUC_UNUSED, - int vf G_GNUC_UNUSED, - char **vfname G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get virtual function name on this platform")); - return -1; -} - -int -virNetDevGetVirtualFunctionInfo(const char *vfname G_GNUC_UNUSED, - char **pfname G_GNUC_UNUSED, - int *vf G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get virtual function info on this platform")); - return -1; -} - -int -virNetDevSysfsFile(char **pf_sysfs_device_link G_GNUC_UNUSED, - const char *ifname G_GNUC_UNUSED, - const char *file G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to get sysfs info on this platform")); - return -1; -} - - -#endif /* !__linux__ */ -#if defined(WITH_LIBNL) - static virMacAddr zeroMAC = { .addr = { 0, 0, 0, 0, 0, 0 } }; @@ -XXX,XX +XXX,XX @@ virNetDevSetNetConfig(const char *linkdev, int vf, return 0; } +#else /* !__linux__ */ +int +virNetDevGetPhysPortID(const char *ifname G_GNUC_UNUSED, + char **physPortID) +{ + /* this actually should never be called, and is just here to + * satisfy the linker. + */ + *physPortID = NULL; + return 0; +} + +int +virNetDevGetPhysPortName(const char *ifname G_GNUC_UNUSED, + char **physPortName) +{ + /* this actually should never be called, and is just here to + * satisfy the linker. + */ + *physPortName = NULL; + return 0; +} + +int +virNetDevGetVirtualFunctions(const char *pfname G_GNUC_UNUSED, + virPCIVirtualFunctionList **vfs G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get virtual functions on this platform")); + return -1; +} + +int +virNetDevIsVirtualFunction(const char *ifname G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to check virtual function status on this platform")); + return -1; +} + +int +virNetDevGetVirtualFunctionIndex(const char *pfname G_GNUC_UNUSED, + const char *vfname G_GNUC_UNUSED, + int *vf_index G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get virtual function index on this platform")); + return -1; +} + +int +virNetDevGetPhysicalFunction(const char *ifname G_GNUC_UNUSED, + char **pfname G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get physical function status on this platform")); + return -1; +} -#else /* defined(WITH_LIBNL) */ +int +virNetDevPFGetVF(const char *pfname G_GNUC_UNUSED, + int vf G_GNUC_UNUSED, + char **vfname G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get virtual function name on this platform")); + return -1; +} + +int +virNetDevGetVirtualFunctionInfo(const char *vfname G_GNUC_UNUSED, + char **pfname G_GNUC_UNUSED, + int *vf G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get virtual function info on this platform")); + return -1; +} + +int +virNetDevSysfsFile(char **pf_sysfs_device_link G_GNUC_UNUSED, + const char *ifname G_GNUC_UNUSED, + const char *file G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to get sysfs info on this platform")); + return -1; +} int @@ -XXX,XX +XXX,XX @@ virNetDevSetVfConfig(const char *ifname G_GNUC_UNUSED, } -#endif /* defined(WITH_LIBNL) */ +#endif /* defined(__linux__) */ VIR_ENUM_IMPL(virNetDevIfState, VIR_NETDEV_IF_STATE_LAST, @@ -XXX,XX +XXX,XX @@ virNetDevGetEthtoolFeatures(const char *ifname, } -# if defined(WITH_LIBNL) - /** * virNetDevGetFamilyId: * This function supplies the devlink family id @@ -XXX,XX +XXX,XX @@ virNetDevSwitchdevFeature(const char *ifname, nlmsg_free(nl_msg); return ret; } -# else -static int -virNetDevSwitchdevFeature(const char *ifname G_GNUC_UNUSED, - virBitmap **out G_GNUC_UNUSED) -{ - return 0; -} -# endif /** diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -XXX,XX +XXX,XX @@ #endif #ifdef __linux__ -# if defined(WITH_LIBNL) -# include "virnetlink.h" -# endif +# include "virnetlink.h" # include <linux/sockios.h> # include <linux/param.h> /* HZ */ # include <linux/in6.h> @@ -XXX,XX +XXX,XX @@ virNetDevBridgeCreateWithIoctl(const char *brname, } #endif -#if defined(WITH_LIBNL) +#if defined(__linux__) int virNetDevBridgeCreate(const char *brname, const virMacAddr *mac) @@ -XXX,XX +XXX,XX @@ virNetDevBridgeCreate(const char *brname, } -#elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR) -int -virNetDevBridgeCreate(const char *brname, - const virMacAddr *mac) -{ - return virNetDevBridgeCreateWithIoctl(brname, mac); -} - - #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFCREATE2) int virNetDevBridgeCreate(const char *brname, @@ -XXX,XX +XXX,XX @@ virNetDevBridgeDeleteWithIoctl(const char *brname) #endif -#if defined(WITH_LIBNL) +#if defined(__linux__) int virNetDevBridgeDelete(const char *brname) { @@ -XXX,XX +XXX,XX @@ virNetDevBridgeDelete(const char *brname) } -#elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR) -int -virNetDevBridgeDelete(const char *brname) -{ - return virNetDevBridgeDeleteWithIoctl(brname); -} - - #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFDESTROY) int virNetDevBridgeDelete(const char *brname) @@ -XXX,XX +XXX,XX @@ virNetDevBridgeSetVlanFiltering(const char *brname G_GNUC_UNUSED, #endif -#if defined(WITH_LIBNL) +#if defined(__linux__) # ifndef NTF_SELF # define NTF_SELF 0x02 diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevip.c +++ b/src/util/virnetdevip.c @@ -XXX,XX +XXX,XX @@ VIR_LOG_INIT("util.netdevip"); -#if defined(WITH_LIBNL) +#if defined(__linux__) static int virNetDevGetIPAddressBinary(virSocketAddr *addr, void **data, size_t *len) @@ -XXX,XX +XXX,XX @@ virNetDevIPRouteAdd(const char *ifname, } -#else /* defined(WITH_LIBNL) */ +static int +virNetDevIPGetAcceptRA(const char *ifname) +{ + g_autofree char *path = NULL; + g_autofree char *buf = NULL; + char *suffix; + int accept_ra = -1; + + path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/accept_ra", + ifname ? ifname : "all"); + + if ((virFileReadAll(path, 512, &buf) < 0) || + (virStrToLong_i(buf, &suffix, 10, &accept_ra) < 0)) + return -1; + + return accept_ra; +} + +/** + * virNetDevIPCheckIPv6Forwarding + * + * This function checks if IPv6 routes have the RTF_ADDRCONF flag set, + * indicating they have been created by the kernel's RA configuration + * handling. These routes are subject to being flushed when ipv6 + * forwarding is enabled unless accept_ra is explicitly set to "2". + * This will most likely result in ipv6 networking being broken. + * + * Returns: true if it is safe to enable forwarding, or false if + * breakable routes are found. + * + **/ +bool +virNetDevIPCheckIPv6Forwarding(void) +{ + int len; + char *cur; + g_autofree char *buf = NULL; + /* lines are 150 chars */ + enum {MAX_ROUTE_SIZE = 150*1000000}; + + /* This is /proc/sys/net/ipv6/conf/all/accept_ra */ + int all_accept_ra = virNetDevIPGetAcceptRA(NULL); + + /* Read ipv6 routes */ + if ((len = virFileReadAll(PROC_NET_IPV6_ROUTE, + MAX_ROUTE_SIZE, &buf)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to read %1$s for ipv6 forwarding checks"), + PROC_NET_IPV6_ROUTE); + return false; + } + + /* Dropping the last character to stop the loop */ + if (len > 0) + buf[len-1] = '\0'; + + cur = buf; + while (cur) { + char route[33], flags[9], iface[9]; + unsigned int flags_val; + char *iface_val; + int num; + char *nl = strchr(cur, '\n'); + + if (nl) + *nl++ = '\0'; + + num = sscanf(cur, "%32s %*s %*s %*s %*s %*s %*s %*s %8s %8s", + route, flags, iface); + + cur = nl; + if (num != 3) { + VIR_DEBUG("Failed to parse route line: %s", cur); + continue; + } + + if (virStrToLong_ui(flags, NULL, 16, &flags_val)) { + VIR_DEBUG("Failed to parse flags: %s", flags); + continue; + } + + /* This is right justified, strip leading spaces */ + iface_val = &iface[0]; + while (*iface_val && g_ascii_isspace(*iface_val)) + iface_val++; + + VIR_DEBUG("%s iface %s flags %s : RTF_ADDRCONF %sset", + route, iface_val, flags, + (flags_val & RTF_ADDRCONF ? "" : "not ")); + + if (flags_val & RTF_ADDRCONF) { + int ret = virNetDevIPGetAcceptRA(iface_val); + VIR_DEBUG("%s reports accept_ra of %d", + iface_val, ret); + /* If the interface for this autoconfigured route + * has accept_ra == 1, or it is default and the "all" + * value of accept_ra == 1, it will be subject to + * flushing if forwarding is enabled. + */ + if (ret == 1 || (ret == 0 && all_accept_ra == 1)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Check the host setup: interface %1$s has kernel autoconfigured IPv6 routes and enabling forwarding without accept_ra set to 2 will cause the kernel to flush them, breaking networking."), + iface_val); + return false; + } + } + } + return true; +} + + +#else /* defined(__linux__) */ int @@ -XXX,XX +XXX,XX @@ virNetDevIPRouteAdd(const char *ifname, return 0; } -#endif /* defined(HAVE_LIBNL) */ - - -#if defined(__linux__) - -static int -virNetDevIPGetAcceptRA(const char *ifname) -{ - g_autofree char *path = NULL; - g_autofree char *buf = NULL; - char *suffix; - int accept_ra = -1; - - path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/accept_ra", - ifname ? ifname : "all"); - - if ((virFileReadAll(path, 512, &buf) < 0) || - (virStrToLong_i(buf, &suffix, 10, &accept_ra) < 0)) - return -1; - - return accept_ra; -} - -/** - * virNetDevIPCheckIPv6Forwarding - * - * This function checks if IPv6 routes have the RTF_ADDRCONF flag set, - * indicating they have been created by the kernel's RA configuration - * handling. These routes are subject to being flushed when ipv6 - * forwarding is enabled unless accept_ra is explicitly set to "2". - * This will most likely result in ipv6 networking being broken. - * - * Returns: true if it is safe to enable forwarding, or false if - * breakable routes are found. - * - **/ -bool -virNetDevIPCheckIPv6Forwarding(void) -{ - int len; - char *cur; - g_autofree char *buf = NULL; - /* lines are 150 chars */ - enum {MAX_ROUTE_SIZE = 150*1000000}; - - /* This is /proc/sys/net/ipv6/conf/all/accept_ra */ - int all_accept_ra = virNetDevIPGetAcceptRA(NULL); - - /* Read ipv6 routes */ - if ((len = virFileReadAll(PROC_NET_IPV6_ROUTE, - MAX_ROUTE_SIZE, &buf)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to read %1$s for ipv6 forwarding checks"), - PROC_NET_IPV6_ROUTE); - return false; - } - - /* Dropping the last character to stop the loop */ - if (len > 0) - buf[len-1] = '\0'; - - cur = buf; - while (cur) { - char route[33], flags[9], iface[9]; - unsigned int flags_val; - char *iface_val; - int num; - char *nl = strchr(cur, '\n'); - - if (nl) - *nl++ = '\0'; - - num = sscanf(cur, "%32s %*s %*s %*s %*s %*s %*s %*s %8s %8s", - route, flags, iface); - - cur = nl; - if (num != 3) { - VIR_DEBUG("Failed to parse route line: %s", cur); - continue; - } - - if (virStrToLong_ui(flags, NULL, 16, &flags_val)) { - VIR_DEBUG("Failed to parse flags: %s", flags); - continue; - } - - /* This is right justified, strip leading spaces */ - iface_val = &iface[0]; - while (*iface_val && g_ascii_isspace(*iface_val)) - iface_val++; - - VIR_DEBUG("%s iface %s flags %s : RTF_ADDRCONF %sset", - route, iface_val, flags, - (flags_val & RTF_ADDRCONF ? "" : "not ")); - - if (flags_val & RTF_ADDRCONF) { - int ret = virNetDevIPGetAcceptRA(iface_val); - VIR_DEBUG("%s reports accept_ra of %d", - iface_val, ret); - /* If the interface for this autoconfigured route - * has accept_ra == 1, or it is default and the "all" - * value of accept_ra == 1, it will be subject to - * flushing if forwarding is enabled. - */ - if (ret == 1 || (ret == 0 && all_accept_ra == 1)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Check the host setup: interface %1$s has kernel autoconfigured IPv6 routes and enabling forwarding without accept_ra set to 2 will cause the kernel to flush them, breaking networking."), - iface_val); - return false; - } - } - } - return true; -} -#else bool virNetDevIPCheckIPv6Forwarding(void) diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, "passthrough", ); -#if defined(WITH_LIBNL) +#if defined(__linux__) # include <fcntl.h> # include <net/if.h> @@ -XXX,XX +XXX,XX @@ int virNetDevMacVLanRestartWithVPortProfile(const char *cr_ifname, } -#else /* ! WITH_LIBNL */ +#else /* ! __linux__ */ bool virNetDevMacVLanIsMacvtap(const char *ifname G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", @@ -XXX,XX +XXX,XX @@ int virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname G_GNUC_UNUSE _("Cannot create macvlan devices on this platform")); return -1; } -#endif /* ! WITH_LIBNL */ +#endif /* ! __linux__ */ diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -XXX,XX +XXX,XX @@ VIR_LOG_INIT("util.netdevveth"); -#if defined(WITH_LIBNL) static int virNetDevVethCreateInternal(const char *veth1, const char *veth2) { @@ -XXX,XX +XXX,XX @@ virNetDevVethDeleteInternal(const char *veth) { return virNetlinkDelLink(veth, NULL); } -#else -static int -virNetDevVethCreateInternal(const char *veth1, const char *veth2) -{ - g_autoptr(virCommand) cmd = virCommandNew("ip"); - virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth", - "peer", "name", veth2, NULL); - - return virCommandRun(cmd, NULL); -} - -static int -virNetDevVethDeleteInternal(const char *veth) -{ - int status; - g_autoptr(virCommand) cmd = virCommandNewArgList("ip", "link", - "del", veth, NULL); - - if (virCommandRun(cmd, &status) < 0) - return -1; - - if (status != 0) { - if (!virNetDevExists(veth)) { - VIR_DEBUG("Device %s already deleted (by kernel namespace cleanup)", veth); - return 0; - } - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to delete veth device %1$s"), veth); - return -1; - } - - return 0; -} -#endif /* WITH_LIBNL */ /** * virNetDevVethCreate: diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -XXX,XX +XXX,XX @@ VIR_ENUM_IMPL(virNetDevVPortProfileOp, "no-op", ); -#if defined(WITH_LIBNL) +#if defined(__linux__) # include <fcntl.h> @@ -XXX,XX +XXX,XX @@ int virNetDevVPortProfileMerge3(virNetDevVPortProfile **result, } -#if defined(WITH_LIBNL) +#if defined(__linux__) static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = { @@ -XXX,XX +XXX,XX @@ virNetDevVPortProfileDisassociate(const char *macvtap_ifname, return rc; } -#else /* !WITH_LIBNL */ +#else /* !__linux__ */ int virNetDevVPortProfileAssociate(const char *macvtap_ifname G_GNUC_UNUSED, const virNetDevVPortProfile *virtPort G_GNUC_UNUSED, const virMacAddr *macvtap_macaddr G_GNUC_UNUSED, @@ -XXX,XX +XXX,XX @@ int virNetDevVPortProfileDisassociate(const char *macvtap_ifname G_GNUC_UNUSED, _("Virtual port profile association not supported on this platform")); return -1; } -#endif /* !WITH_LIBNL */ +#endif /* !__linux__ */ diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -XXX,XX +XXX,XX @@ VIR_LOG_INIT("util.netlink"); #define NETLINK_ACK_TIMEOUT_S (2*1000) -#if defined(WITH_LIBNL) +#if defined(__linux__) # include <linux/veth.h> @@ -XXX,XX +XXX,XX @@ virNetlinkEventRemoveClient(int watch, const virMacAddr *macaddr, #else -# if defined(__linux__) -static const char *unsupported = N_("libnl was not available at build time"); -# else static const char *unsupported = N_("not supported on non-linux platforms"); -# endif int virNetlinkStartup(void) @@ -XXX,XX +XXX,XX @@ virNetlinkGetErrorCode(struct nlmsghdr *resp G_GNUC_UNUSED, return -EINVAL; } -#endif /* WITH_LIBNL */ +#endif /* __linux__ */ diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -XXX,XX +XXX,XX @@ #include "internal.h" #include "virmacaddr.h" -#if defined(WITH_LIBNL) +#if defined(__linux__) # include <netlink/msg.h> # include <linux/if_bridge.h> @@ -XXX,XX +XXX,XX @@ struct sockaddr_nl; struct nlattr; struct nlmsghdr; -#endif /* WITH_LIBNL */ +#endif /* __linux__ */ int virNetlinkStartup(void); void virNetlinkShutdown(void); diff --git a/tests/virnetdevtest.c b/tests/virnetdevtest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -XXX,XX +XXX,XX @@ testVirNetDevGetLinkInfo(const void *opaque) return 0; } -# if defined(WITH_LIBNL) - int (*real_virNetDevSendVfSetLinkRequest)(const char *ifname, int vfInfoType, @@ -XXX,XX +XXX,XX @@ testVirNetDevSetVfConfig(const void *opaque G_GNUC_UNUSED) return 0; } -# endif /* defined(WITH_LIBNL) */ - static int mymain(void) { @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_LINK("lo", VIR_NETDEV_IF_STATE_UNKNOWN, 0); DO_TEST_LINK("eth0-broken", VIR_NETDEV_IF_STATE_DOWN, 0); -# if defined(WITH_LIBNL) - if (virTestRun("Set VF MAC", testVirNetDevSetVfMac, NULL) < 0) ret = -1; if (virTestRun("Set VF MAC: missing MAC pointer", testVirNetDevSetVfMissingMac, NULL) < 0) @@ -XXX,XX +XXX,XX @@ mymain(void) if (virTestRun("Set VF Config", testVirNetDevSetVfConfig, NULL) < 0) ret = -1; -# endif /* defined(WITH_LIBNL) */ - return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } --- base-commit: e5299ddf86121d3c792ca271ffcb54900eb19dc3 change-id: 20250308-require-289966671f9d Best regards, -- Akihiko Odaki <akihiko.odaki@daynix.com>
Supersedes: <20250308-require-v1-1-fe6850bf3f30@daynix.com> ("[PATCH] util: Require libnl for Linux") Based on previous discussions, this implements yet another approach to fix builds without libnl for Linux. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> --- Changes in v2: - Rebased. - Link to v1: https://lore.kernel.org/r/20250312-linux-v1-0-e5531bbe9708@daynix.com --- Akihiko Odaki (2): Remove libnl checks specific to Linux virnetlink: Remove stub functions src/libvirt_libnl.syms | 23 +++++ src/libvirt_private.syms | 19 ---- src/meson.build | 6 ++ src/remote/remote_daemon.c | 10 ++- src/util/meson.build | 5 +- src/util/virarptable.c | 2 +- src/util/virnetdev.c | 44 +-------- src/util/virnetdevbridge.c | 29 +----- src/util/virnetlink.c | 216 +++------------------------------------------ src/util/virnetlink.h | 11 +-- tests/virnetdevtest.c | 10 +-- 11 files changed, 64 insertions(+), 311 deletions(-) --- base-commit: 5085c7fd030ed4322608de1128811fc3bf61e201 change-id: 20250312-linux-30e6e1af51a5 Best regards, -- Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Builds for Linux without libnl is broken since commit 582f0966f9b9e2148d8887d072364e2a91aed000 because src/util/virnetdevbridge.c refers to virNetlinkBridgeVlanFilterSet(). A fundamental problem here is that nobody tests such builds. Netlink is a critical part of Linux networking so developers may assume it is readily available, but the libnl dependency check breaks this assumption. Builds without libnl also lack several networking features such as SR-IOV, bridge/tap, switchdev, macvlan, veth, and vlan. This may also contradict with exceptations made by other networking code of libvirt or users. Remove libnl checks specific to Linux to avoid such a problem in libvirt's networking code. More concretely, find patterns like following: #ifdef __linux__ A #ifdef WITH_LIBNL B #endif C #endif And replace them with: #ifdef WITH_LIBNL A B C #endif There are also patterns like following: #ifdef WITH_LIBNL A #elif defined(__linux__) B #endif Replace them with: #ifdef WITH_LIBNL A #endif This change will make less networking features available. Anyone who want these features should enable libnl for the better tested code. It still does not require libnl to build because the client code and some drivers do not need libvirt to configure networking at all. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> --- src/util/virnetdev.c | 44 ++++---------------------------------------- src/util/virnetdevbridge.c | 29 ++++------------------------- tests/virnetdevtest.c | 10 +--------- 3 files changed, 9 insertions(+), 74 deletions(-) diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -XXX,XX +XXX,XX @@ virNetDevGetMaster(const char *ifname, char **master) return 0; } -#elif defined(__linux__) - -/* libnl isn't available, so we can't use netlink. - * Fall back to using sysfs - */ -int -virNetDevGetMaster(const char *ifname, char **master) -{ - g_autofree char *path = NULL; - g_autofree char *canonical = NULL; - - if (virNetDevSysfsFile(&path, ifname, "master") < 0) - return -1; - - if (!(canonical = virFileCanonicalizePath(path))) - return -1; - - *master = g_path_get_basename(canonical); - - VIR_DEBUG("IFLA_MASTER for %s is %s", ifname, *master ? *master : "(none)"); - return 0; -} - #else int @@ -XXX,XX +XXX,XX @@ int virNetDevValidateConfig(const char *ifname G_GNUC_UNUSED, #endif -#ifdef __linux__ +#ifdef WITH_LIBNL int virNetDevSysfsFile(char **pf_sysfs_device_link, const char *ifname, @@ -XXX,XX +XXX,XX @@ virNetDevSysfsDeviceFile(char **pf_sysfs_device_link, const char *ifname, } -# if defined(WITH_LIBNL) - /** * Determine if the device path specified in devpath is a PCI Device * by resolving the 'subsystem'-link in devpath and looking for @@ -XXX,XX +XXX,XX @@ virNetDevGetPCIDevice(const char *devName) return virPCIDeviceNew(vfPCIAddr); } -# endif /* A wrapper to get content of file from ifname SYSFS_NET_DIR @@ -XXX,XX +XXX,XX @@ virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname, return ret; } -#else /* !__linux__ */ +#else /* !WITH_LIBNL */ int virNetDevGetPhysPortID(const char *ifname G_GNUC_UNUSED, char **physPortID) @@ -XXX,XX +XXX,XX @@ virNetDevSysfsFile(char **pf_sysfs_device_link G_GNUC_UNUSED, } -#endif /* !__linux__ */ +#endif /* !WITH_LIBNL */ #if defined(WITH_LIBNL) @@ -XXX,XX +XXX,XX @@ int virNetDevGetRxFilter(const char *ifname, return ret; } -#if __linux__ +#ifdef WITH_LIBNL /** * virNetDevRDMAFeature @@ -XXX,XX +XXX,XX @@ virNetDevGetEthtoolFeatures(const char *ifname, } -# if defined(WITH_LIBNL) - /** * virNetDevGetFamilyId: * This function supplies the devlink family id @@ -XXX,XX +XXX,XX @@ virNetDevSwitchdevFeature(const char *ifname, nlmsg_free(nl_msg); return ret; } -# else -static int -virNetDevSwitchdevFeature(const char *ifname G_GNUC_UNUSED, - virBitmap **out G_GNUC_UNUSED) -{ - return 0; -} -# endif /** diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -XXX,XX +XXX,XX @@ static int virNetDevBridgeGet(const char *brname, } #endif /* __linux__ */ -#if defined(__linux__) +#if defined(WITH_LIBNL) static int virNetDevBridgePortSet(const char *brname, const char *ifname, @@ -XXX,XX +XXX,XX @@ virNetDevBridgePortSetIsolated(const char *brname G_GNUC_UNUSED, * * Returns 0 in case of success or -1 on failure */ -#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR) +#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR) && defined(WITH_LIBNL) static int virNetDevBridgeCreateWithIoctl(const char *brname, const virMacAddr *mac) @@ -XXX,XX +XXX,XX @@ virNetDevBridgeCreateWithIoctl(const char *brname, return 0; } -#endif -#if defined(WITH_LIBNL) int virNetDevBridgeCreate(const char *brname, const virMacAddr *mac) @@ -XXX,XX +XXX,XX @@ virNetDevBridgeCreate(const char *brname, } -#elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR) -int -virNetDevBridgeCreate(const char *brname, - const virMacAddr *mac) -{ - return virNetDevBridgeCreateWithIoctl(brname, mac); -} - - #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFCREATE2) int virNetDevBridgeCreate(const char *brname, @@ -XXX,XX +XXX,XX @@ virNetDevBridgeCreate(const char *brname, * * Returns 0 in case of success or an errno code in case of failure. */ -#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR) +#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR) && defined(WITH_LIBNL) static int virNetDevBridgeDeleteWithIoctl(const char *brname) { @@ -XXX,XX +XXX,XX @@ virNetDevBridgeDeleteWithIoctl(const char *brname) return 0; } -#endif -#if defined(WITH_LIBNL) int virNetDevBridgeDelete(const char *brname) { @@ -XXX,XX +XXX,XX @@ virNetDevBridgeDelete(const char *brname) } -#elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR) -int -virNetDevBridgeDelete(const char *brname) -{ - return virNetDevBridgeDeleteWithIoctl(brname); -} - - #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFDESTROY) int virNetDevBridgeDelete(const char *brname) @@ -XXX,XX +XXX,XX @@ int virNetDevBridgeDelete(const char *brname G_GNUC_UNUSED) * * Returns 0 in case of success or an errno code in case of failure. */ -#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDIF) +#if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDIF) && defined(WITH_LIBNL) int virNetDevBridgeAddPort(const char *brname, const char *ifname, const virNetDevVlan *virtVlan) diff --git a/tests/virnetdevtest.c b/tests/virnetdevtest.c index XXXXXXX..XXXXXXX 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -XXX,XX +XXX,XX @@ #define LIBVIRT_VIRNETDEVPRIV_H_ALLOW -#ifdef __linux__ +#ifdef WITH_LIBNL # include "virmock.h" # include "virnetdevpriv.h" @@ -XXX,XX +XXX,XX @@ testVirNetDevGetLinkInfo(const void *opaque) return 0; } -# if defined(WITH_LIBNL) - int (*real_virNetDevSendVfSetLinkRequest)(const char *ifname, int vfInfoType, @@ -XXX,XX +XXX,XX @@ testVirNetDevSetVfConfig(const void *opaque G_GNUC_UNUSED) return 0; } -# endif /* defined(WITH_LIBNL) */ - static int mymain(void) { @@ -XXX,XX +XXX,XX @@ mymain(void) DO_TEST_LINK("lo", VIR_NETDEV_IF_STATE_UNKNOWN, 0); DO_TEST_LINK("eth0-broken", VIR_NETDEV_IF_STATE_DOWN, 0); -# if defined(WITH_LIBNL) - if (virTestRun("Set VF MAC", testVirNetDevSetVfMac, NULL) < 0) ret = -1; if (virTestRun("Set VF MAC: missing MAC pointer", testVirNetDevSetVfMissingMac, NULL) < 0) @@ -XXX,XX +XXX,XX @@ mymain(void) if (virTestRun("Set VF Config", testVirNetDevSetVfConfig, NULL) < 0) ret = -1; -# endif /* defined(WITH_LIBNL) */ - return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.50.1
virnetlink provides stub functions when libnl is not available, but this approach caused a few problems: - Commit 582f0966f9b9e2148d8887d072364e2a91aed000 broke builds without libnl for Linux because virNetlinkBridgeVlanFilterSet() lacked a stub. - A call to virNetlinkEventServiceStopAll() stub in src/remote/remote_daemon.c resulted in extra debug logs. Instead of providing stub functions, let callers check the availability of libnl. Callers are also replaced with stub functions in most cases so this approach requires less code and less error-prone. Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> --- src/libvirt_libnl.syms | 23 +++++ src/libvirt_private.syms | 19 ---- src/meson.build | 6 ++ src/remote/remote_daemon.c | 10 ++- src/util/meson.build | 5 +- src/util/virarptable.c | 2 +- src/util/virnetlink.c | 216 +++------------------------------------------ src/util/virnetlink.h | 11 +-- 8 files changed, 55 insertions(+), 237 deletions(-) diff --git a/src/libvirt_libnl.syms b/src/libvirt_libnl.syms new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/src/libvirt_libnl.syms @@ -XXX,XX +XXX,XX @@ +# util/virnetlink.h +virNetlinkCommand; +virNetlinkDelLink; +virNetlinkDumpCommand; +virNetlinkDumpLink; +virNetlinkEventAddClient; +virNetlinkEventRemoveClient; +virNetlinkEventServiceIsRunning; +virNetlinkEventServiceLocalPid; +virNetlinkEventServiceStart; +virNetlinkEventServiceStop; +virNetlinkEventServiceStopAll; +virNetlinkGetErrorCode; +virNetlinkGetNeighbor; +virNetlinkNewLink; +virNetlinkShutdown; +virNetlinkStartup; + + +# Let emacs know we want case-insensitive sorting +# Local Variables: +# sort-fold-case: t +# End: diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index XXXXXXX..XXXXXXX 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -XXX,XX +XXX,XX @@ virNetDevVPortProfileOpTypeFromString; virNetDevVPortProfileOpTypeToString; -# util/virnetlink.h -virNetlinkCommand; -virNetlinkDelLink; -virNetlinkDumpCommand; -virNetlinkDumpLink; -virNetlinkEventAddClient; -virNetlinkEventRemoveClient; -virNetlinkEventServiceIsRunning; -virNetlinkEventServiceLocalPid; -virNetlinkEventServiceStart; -virNetlinkEventServiceStop; -virNetlinkEventServiceStopAll; -virNetlinkGetErrorCode; -virNetlinkGetNeighbor; -virNetlinkNewLink; -virNetlinkShutdown; -virNetlinkStartup; - - # util/virnodesuspend.h virNodeSuspend; virNodeSuspendGetTargetMask; diff --git a/src/meson.build b/src/meson.build index XXXXXXX..XXXXXXX 100644 --- a/src/meson.build +++ b/src/meson.build @@ -XXX,XX +XXX,XX @@ else sym_files += 'libvirt_hyperv.syms' endif +if conf.has('WITH_LIBNL') + used_sym_files += 'libvirt_libnl.syms' +else + sym_files += 'libvirt_libnl.syms' +endif + # variables filled by subdirectories libvirt_libs = [] diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c index XXXXXXX..XXXXXXX 100644 --- a/src/remote/remote_daemon.c +++ b/src/remote/remote_daemon.c @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { } umask(old_umask); +#ifdef WITH_LIBNL if (virNetlinkStartup() < 0) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } +#endif if (!(dmn = virNetDaemonNew())) { ret = VIR_DAEMON_ERR_DRIVER; @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { goto cleanup; } -#if defined(__linux__) && defined(NETLINK_ROUTE) +#if defined(WITH_LIBNL) && defined(NETLINK_ROUTE) /* Register the netlink event service for NETLINK_ROUTE */ if (virNetlinkEventServiceStart(NETLINK_ROUTE, 0) < 0) { ret = VIR_DAEMON_ERR_NETWORK; @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { } #endif -#if defined(__linux__) && defined(NETLINK_KOBJECT_UEVENT) +#if defined(WITH_LIBNL) && defined(NETLINK_KOBJECT_UEVENT) /* Register the netlink event service for NETLINK_KOBJECT_UEVENT */ if (virNetlinkEventServiceStart(NETLINK_KOBJECT_UEVENT, 1) < 0) { ret = VIR_DAEMON_ERR_NETWORK; @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { 0, "shutdown", NULL, NULL); cleanup: +#ifdef WITH_LIBNL virNetlinkEventServiceStopAll(); +#endif if (g_atomic_int_compare_and_exchange(&driversInitialized, 1, 0)) { /* NB: Possible issue with timing window between driversInitialized @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) { virObjectUnref(srv); virObjectUnref(dmn); +#ifdef WITH_LIBNL virNetlinkShutdown(); +#endif if (pid_file_fd != -1) virPidFileReleasePath(pid_file, pid_file_fd); diff --git a/src/util/meson.build b/src/util/meson.build index XXXXXXX..XXXXXXX 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -XXX,XX +XXX,XX @@ util_sources = [ 'virnetdevveth.c', 'virnetdevvlan.c', 'virnetdevvportprofile.c', - 'virnetlink.c', 'virnodesuspend.c', 'virnuma.c', 'virnvme.c', @@ -XXX,XX +XXX,XX @@ util_sources = [ 'virxml.c', ] +if conf.has('WITH_LIBNL') + util_sources += 'virnetlink.c' +endif + util_public_sources = files( 'virerror.c', 'virevent.c', diff --git a/src/util/virarptable.c b/src/util/virarptable.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virarptable.c +++ b/src/util/virarptable.c @@ -XXX,XX +XXX,XX @@ VIR_LOG_INIT("util.arptable"); -#ifdef __linux__ +#ifdef WITH_LIBNL # define NDA_RTA(r) \ ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -XXX,XX +XXX,XX @@ VIR_LOG_INIT("util.netlink"); #define NETLINK_ACK_TIMEOUT_S (2*1000) -#if defined(WITH_LIBNL) +#include <linux/veth.h> -# include <linux/veth.h> - -# define NETLINK_MSG_NEST_START(msg, container, attrtype) \ +#define NETLINK_MSG_NEST_START(msg, container, attrtype) \ do { \ container = nla_nest_start(msg, attrtype); \ if (!container) { \ @@ -XXX,XX +XXX,XX @@ do { \ } \ } while (0) -# define NETLINK_MSG_NEST_END(msg, container) \ +#define NETLINK_MSG_NEST_END(msg, container) \ do { nla_nest_end(msg, container); } while (0) /* @@ -XXX,XX +XXX,XX @@ do { nla_nest_end(msg, container); } while (0) * complain about @data not being a pointer type: * error: the address of 'foo' will always evaluate as 'true' [-Werror=address] */ -# define NETLINK_MSG_PUT(msg, attrtype, datalen, data) \ +#define NETLINK_MSG_PUT(msg, attrtype, datalen, data) \ do { \ const void *dataptr = data; \ if (dataptr && nla_put(msg, attrtype, datalen, dataptr) < 0) { \ @@ -XXX,XX +XXX,XX @@ do { \ } \ } while (0) -# define NETLINK_MSG_APPEND(msg, datalen, dataptr) \ +#define NETLINK_MSG_APPEND(msg, datalen, dataptr) \ do { \ if (nlmsg_append(msg, dataptr, datalen, NLMSG_ALIGNTO) < 0) { \ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \ @@ -XXX,XX +XXX,XX @@ struct virNetlinkEventHandle { int deleted; }; -# define virNetlinkAlloc nl_socket_alloc -# define virNetlinkSetBufferSize nl_socket_set_buffer_size -# define virNetlinkFree nl_socket_free +#define virNetlinkAlloc nl_socket_alloc +#define virNetlinkSetBufferSize nl_socket_set_buffer_size +#define virNetlinkFree nl_socket_free typedef struct nl_sock virNetlinkHandle; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetlinkHandle, virNetlinkFree); @@ -XXX,XX +XXX,XX @@ static int nextWatch = 1; /* Allocate extra slots for virEventPollHandle/virEventPollTimeout records in this multiple */ -# define NETLINK_EVENT_ALLOC_EXTENT 10 +#define NETLINK_EVENT_ALLOC_EXTENT 10 /* Linux kernel supports up to MAX_LINKS (32 at the time) individual * netlink protocols. */ @@ -XXX,XX +XXX,XX @@ virNetlinkDumpLink(const char *ifname, int ifindex, if (ifname) NETLINK_MSG_PUT(nl_msg, IFLA_IFNAME, (strlen(ifname) + 1), ifname); -# ifdef RTEXT_FILTER_VF +#ifdef RTEXT_FILTER_VF /* if this filter exists in the kernel's netlink implementation, * we need to set it, otherwise the response message will not * contain the IFLA_VFINFO_LIST that we're looking for. @@ -XXX,XX +XXX,XX @@ virNetlinkDumpLink(const char *ifname, int ifindex, NETLINK_MSG_PUT(nl_msg, IFLA_EXT_MASK, sizeof(ifla_ext_mask), &ifla_ext_mask); } -# endif +#endif if (virNetlinkTalk(ifname, nl_msg, src_pid, dst_pid, &resp, &resp_len, &error, NULL) < 0) { @@ -XXX,XX +XXX,XX @@ virNetlinkEventRemoveClient(int watch, const virMacAddr *macaddr, return -1; } - -#else - -# if defined(__linux__) -static const char *unsupported = N_("libnl was not available at build time"); -# else -static const char *unsupported = N_("not supported on non-linux platforms"); -# endif - -int -virNetlinkStartup(void) -{ - return 0; -} - -void -virNetlinkShutdown(void) -{ - return; -} - -int virNetlinkCommand(struct nl_msg *nl_msg G_GNUC_UNUSED, - struct nlmsghdr **resp G_GNUC_UNUSED, - unsigned int *respbuflen G_GNUC_UNUSED, - uint32_t src_pid G_GNUC_UNUSED, - uint32_t dst_pid G_GNUC_UNUSED, - unsigned int protocol G_GNUC_UNUSED, - unsigned int groups G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -virNetlinkDumpCommand(struct nl_msg *nl_msg G_GNUC_UNUSED, - virNetlinkDumpCallback callback G_GNUC_UNUSED, - uint32_t src_pid G_GNUC_UNUSED, - uint32_t dst_pid G_GNUC_UNUSED, - unsigned int protocol G_GNUC_UNUSED, - unsigned int groups G_GNUC_UNUSED, - void *opaque G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -virNetlinkDumpLink(const char *ifname G_GNUC_UNUSED, - int ifindex G_GNUC_UNUSED, - void **nlData G_GNUC_UNUSED, - struct nlattr **tb G_GNUC_UNUSED, - uint32_t src_pid G_GNUC_UNUSED, - uint32_t dst_pid G_GNUC_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Unable to dump link info on this platform")); - return -1; -} - - -int -virNetlinkDelLink(const char *ifname G_GNUC_UNUSED, - virNetlinkTalkFallback fallback G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - - -int -virNetlinkNewLink(const char *ifname G_GNUC_UNUSED, - const char *type G_GNUC_UNUSED, - virNetlinkNewLinkData *extra_args G_GNUC_UNUSED, - int *error G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - - -int -virNetlinkBridgeVlanFilterSet(const char *ifname G_GNUC_UNUSED, - const unsigned short unusedflags G_GNUC_UNUSED, - const short vid G_GNUC_UNUSED, - int *error) -{ - *error = 0; - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -virNetlinkBridgeVlanFilterDel(const char *ifname G_GNUC_UNUSED, - const short vid G_GNUC_UNUSED, - int *error G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -virNetlinkGetNeighbor(void **nlData G_GNUC_UNUSED, - uint32_t src_pid G_GNUC_UNUSED, - uint32_t dst_pid G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - - -/** - * stopNetlinkEventServer: stop the monitor to receive netlink - * messages for libvirtd - */ -int virNetlinkEventServiceStop(unsigned int protocol G_GNUC_UNUSED) -{ - VIR_DEBUG("%s", unsupported); - return 0; -} - -/** - * stopNetlinkEventServerAll: stop all the monitors to receive netlink - * messages for libvirtd - */ -int virNetlinkEventServiceStopAll(void) -{ - VIR_DEBUG("%s", unsupported); - return 0; -} - -/** - * startNetlinkEventServer: start a monitor to receive netlink - * messages for libvirtd - */ -int virNetlinkEventServiceStart(unsigned int protocol G_GNUC_UNUSED, - unsigned int groups G_GNUC_UNUSED) -{ - VIR_DEBUG("%s", unsupported); - return 0; -} - -/** - * virNetlinkEventServiceIsRunning: returns if the netlink event - * service is running. - */ -bool virNetlinkEventServiceIsRunning(unsigned int protocol G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return false; -} - -int virNetlinkEventServiceLocalPid(unsigned int protocol G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -/** - * virNetlinkEventAddClient: register a callback for handling of - * netlink messages - */ -int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB G_GNUC_UNUSED, - virNetlinkEventRemoveCallback removeCB G_GNUC_UNUSED, - void *opaque G_GNUC_UNUSED, - const virMacAddr *macaddr G_GNUC_UNUSED, - unsigned int protocol G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -/** - * virNetlinkEventRemoveClient: unregister a callback from a netlink monitor - */ -int virNetlinkEventRemoveClient(int watch G_GNUC_UNUSED, - const virMacAddr *macaddr G_GNUC_UNUSED, - unsigned int protocol G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - - -int -virNetlinkGetErrorCode(struct nlmsghdr *resp G_GNUC_UNUSED, - unsigned int recvbuflen G_GNUC_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -EINVAL; -} - -#endif /* WITH_LIBNL */ diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index XXXXXXX..XXXXXXX 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -XXX,XX +XXX,XX @@ struct nl_msg * virNetlinkMsgNew(int nlmsgtype, int nlmsgflags); -#else - -struct nl_msg; -struct sockaddr_nl; -struct nlattr; -struct nlmsghdr; - -#endif /* WITH_LIBNL */ - int virNetlinkStartup(void); void virNetlinkShutdown(void); @@ -XXX,XX +XXX,XX @@ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, */ int virNetlinkEventRemoveClient(int watch, const virMacAddr *macaddr, unsigned int protocol); + +#endif /* WITH_LIBNL */ -- 2.50.1