/* * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "utils/bullseye.h" #include "vlogger/vlogger.h" #include "netlink_compatibility.h" #include "vma/util/if.h" #define MODULE_NAME "nl_wrapper:" #define nl_logerr __log_err #define nl_logwarn __log_warn #define nl_logdbg __log_dbg extern void link_event_callback(nl_object* obj); extern void neigh_event_callback(nl_object* obj); extern void route_event_callback(nl_object* obj); #ifdef HAVE_LIBNL3 nl_sock* nl_socket_handle_alloc() { return nl_socket_alloc(); } void nl_socket_handle_free(struct nl_sock * sock) { nl_socket_free(sock); } void neigh_callback(nl_cache* , nl_object* obj, int, void*) { neigh_event_callback(obj); } void link_callback(nl_cache* , nl_object* obj, int, void*) { link_event_callback(obj); } void route_callback(nl_cache* , nl_object* obj, int, void*) { route_event_callback(obj); } void nl_socket_handle_disable_seq_check(nl_socket_handle* handle) { return nl_socket_disable_seq_check(handle); } nl_cache_mngr* nl_cache_mngr_compatible_alloc(nl_socket_handle* handle, int protocol, int flags) { nl_cache_mngr* cache_mngr; /* allocate temporary 10 nl_sockets for marking the first 10 bits of user_port_map[0] (@[libnl/lib/socket.c]) as workaround * to avoid conflict between the cache manager's internal sync socket and other netlink sockets on same process */ struct nl_sock* tmp_socket_arr[10]; for (int i=0; i<10; i++) { tmp_socket_arr[i] = nl_socket_handle_alloc(); } int err = nl_cache_mngr_alloc(handle, protocol, flags, &cache_mngr); // free the temporary sockets after cache manager was allocated and bounded the sync socket for (int i=0; i<10; i++) { nl_socket_free(tmp_socket_arr[i]); } BULLSEYE_EXCLUDE_BLOCK_START if (err) { nl_logerr("Fail to allocate cache manager, error=%s", nl_geterror(err)); return NULL; } int nl_socket_fd = nl_socket_get_fd(handle); if (fcntl(nl_socket_fd, F_SETFD, FD_CLOEXEC) != 0) { nl_logwarn("Fail in fctl, error = %d", errno); } BULLSEYE_EXCLUDE_BLOCK_END return cache_mngr; } int nl_cache_mngr_compatible_add(struct nl_cache_mngr* mngr, const char* name, change_func_t cb, void* data, struct nl_cache** result){ int err = nl_cache_mngr_add(mngr, name, cb, data, result); BULLSEYE_EXCLUDE_BLOCK_START if (err) { errno = ELIBEXEC; nl_logerr("Fail to add to cache manager, error=%s", nl_geterror(err)); } BULLSEYE_EXCLUDE_BLOCK_END return err; } in_addr_t nl_object_get_compatible_gateway(struct rtnl_route* nl_route_obj) { struct rtnl_nexthop *nh; nh = rtnl_route_nexthop_n(nl_route_obj, 0); if (nh) { struct nl_addr * addr; addr = rtnl_route_nh_get_gateway(nh); if (addr) { return *(in_addr_t *) nl_addr_get_binary_addr(addr); } } return INADDR_ANY; } int nl_object_get_compatible_oif(struct rtnl_route* nl_route_obj) { struct rtnl_nexthop *nh; nh = rtnl_route_nexthop_n(nl_route_obj, 0); if (nh) { return rtnl_route_nh_get_ifindex(nh); } return -1; } int nl_object_get_compatible_metric(struct rtnl_route* nl_route_obj, int attr) { uint32_t val; int rc = rtnl_route_get_metric(nl_route_obj, attr, &val); if (rc == 0) { return val; } nl_logdbg("Fail parsing route metric %d error=%d\n", attr, rc); return 0; } #else //HAVE_LIBNL1 nl_handle* nl_socket_handle_alloc() { return nl_handle_alloc(); } void nl_socket_handle_free(struct nl_handle* handle) { nl_handle_destroy(handle); } void neigh_callback(nl_cache* , nl_object* obj, int) { neigh_event_callback(obj); } void link_callback(nl_cache* , nl_object* obj, int) { link_event_callback(obj); } void route_callback(nl_cache* , nl_object* obj, int) { route_event_callback(obj); } void nl_socket_handle_disable_seq_check(nl_socket_handle* handle) { return nl_disable_sequence_check(handle); } nl_cache_mngr* nl_cache_mngr_compatible_alloc(nl_socket_handle* handle, int protocol, int flags) { nl_cache_mngr* cache_mgr = nl_cache_mngr_alloc(handle, protocol, flags); BULLSEYE_EXCLUDE_BLOCK_START if (!cache_mgr) { nl_logerr("Fail to allocate cache manager"); } int nl_socket_fd = nl_socket_get_fd(handle); if (fcntl(nl_socket_fd, F_SETFD, FD_CLOEXEC) != 0) { nl_logwarn("Fail in fctl, error = %d", errno); } BULLSEYE_EXCLUDE_BLOCK_END return cache_mgr; } int nl_cache_mngr_compatible_add(struct nl_cache_mngr* mngr, const char* name, change_func_t cb, void* , struct nl_cache** result){ *result = nl_cache_mngr_add(mngr, name, cb); if (*result == NULL) { errno = ELIBEXEC; nl_logerr("Fail adding to cache manager, error=%d %s\n", nl_get_errno(), nl_geterror()); return -1; } return 0; } in_addr_t nl_object_get_compatible_gateway(struct rtnl_route* nl_route_obj) { struct nl_addr * addr; addr = rtnl_route_get_gateway(nl_route_obj); if (addr) { return *(in_addr_t *) nl_addr_get_binary_addr(addr); } return INADDR_ANY; } int nl_object_get_compatible_oif(struct rtnl_route* nl_route_obj) { return rtnl_route_get_oif(nl_route_obj); } int nl_object_get_compatible_metric(struct rtnl_route* nl_route_obj, int attr) { uint32_t val = rtnl_route_get_metric(nl_route_obj, attr); if (val == UINT_MAX) { nl_logdbg("Fail parsing route metric %d error=%d\n", attr, val); return 0; } return val; } #endif