2015-09-14 18:05:03 +02:00
|
|
|
/** Netlink related functions.
|
2015-08-22 17:42:02 +02:00
|
|
|
*
|
2016-06-08 23:21:42 +02:00
|
|
|
* VILLASnode uses libnl3 to talk to the Linux kernel to gather networking related information
|
2015-08-22 17:42:02 +02:00
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2017-03-03 20:20:13 -04:00
|
|
|
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
2017-04-27 12:56:43 +02:00
|
|
|
* @license GNU General Public License (version 3)
|
|
|
|
*
|
|
|
|
* VILLASnode
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2015-08-22 17:42:02 +02:00
|
|
|
*********************************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <netlink/route/route.h>
|
2015-09-14 18:05:03 +02:00
|
|
|
#include <netlink/route/link.h>
|
2015-08-22 17:42:02 +02:00
|
|
|
|
2018-02-06 21:26:12 +01:00
|
|
|
#include <villas/utils.h>
|
|
|
|
#include <villas/kernel/nl.h>
|
2015-08-22 17:42:02 +02:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/** Singleton for global netlink socket */
|
2015-08-22 17:42:02 +02:00
|
|
|
static struct nl_sock *sock = NULL;
|
|
|
|
|
|
|
|
struct nl_sock * nl_init()
|
|
|
|
{
|
2015-09-14 18:05:03 +02:00
|
|
|
int ret;
|
|
|
|
|
2015-08-22 17:42:02 +02:00
|
|
|
if (!sock) {
|
|
|
|
/* Create connection to netlink */
|
|
|
|
sock = nl_socket_alloc();
|
|
|
|
if (!sock)
|
|
|
|
error("Failed to allocate memory");
|
|
|
|
|
2015-09-19 15:28:28 +02:00
|
|
|
ret = nl_connect(sock, NETLINK_ROUTE);
|
|
|
|
if (ret)
|
2015-09-14 18:05:03 +02:00
|
|
|
error("Failed to connect to kernel: %s", nl_geterror(ret));
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/* Fill some caches */
|
|
|
|
struct nl_cache *cache;
|
2015-09-19 15:28:28 +02:00
|
|
|
ret = rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
|
|
|
|
if (ret)
|
2015-09-14 18:05:03 +02:00
|
|
|
error("Failed to get list of interfaces: %s", nl_geterror(ret));
|
|
|
|
|
|
|
|
nl_cache_mngt_provide(cache);
|
2015-08-22 17:42:02 +02:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-08-22 17:42:02 +02:00
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nl_shutdown()
|
|
|
|
{
|
|
|
|
nl_close(sock);
|
|
|
|
nl_socket_free(sock);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-08-22 17:42:02 +02:00
|
|
|
sock = NULL;
|
|
|
|
}
|
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
static int egress_cb(struct nl_msg *msg, void *arg)
|
2015-08-22 17:42:02 +02:00
|
|
|
{
|
2015-09-14 18:05:03 +02:00
|
|
|
struct rtnl_route **route = (struct rtnl_route **) arg;
|
2015-08-22 17:42:02 +02:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
if (rtnl_route_parse(nlmsg_hdr(msg), route))
|
|
|
|
return NL_SKIP;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
return NL_STOP;
|
2015-08-22 17:42:02 +02:00
|
|
|
}
|
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
int nl_get_egress(struct nl_addr *addr)
|
2015-08-22 17:42:02 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct nl_sock *sock = nl_init();
|
2015-10-13 10:12:35 +02:00
|
|
|
struct nl_cb *cb;
|
2015-08-22 17:42:02 +02:00
|
|
|
struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETROUTE, 0);
|
2015-10-13 10:12:35 +02:00
|
|
|
struct rtnl_route *route = NULL;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
|
|
|
/* Build message */
|
2015-08-22 17:42:02 +02:00
|
|
|
struct rtmsg rmsg = {
|
|
|
|
.rtm_family = nl_addr_get_family(addr),
|
|
|
|
.rtm_dst_len = nl_addr_get_prefixlen(addr),
|
|
|
|
};
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-19 15:28:28 +02:00
|
|
|
ret = nlmsg_append(msg, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
|
|
|
|
if (ret)
|
2015-10-13 10:12:35 +02:00
|
|
|
goto out;
|
|
|
|
|
2015-09-19 15:28:28 +02:00
|
|
|
ret = nla_put_addr(msg, RTA_DST, addr);
|
|
|
|
if (ret)
|
2015-10-13 10:12:35 +02:00
|
|
|
goto out;
|
2015-08-22 17:42:02 +02:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/* Send message */
|
|
|
|
ret = nl_send_auto(sock, msg);
|
|
|
|
if (ret < 0)
|
2015-10-13 10:12:35 +02:00
|
|
|
goto out;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/* Hook into receive chain */
|
2016-01-14 22:58:12 +01:00
|
|
|
cb = nl_cb_alloc(NL_CB_CUSTOM);
|
2015-09-14 18:05:03 +02:00
|
|
|
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, egress_cb, &route);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/* Receive message */
|
|
|
|
nl_recvmsgs_report(sock, cb);
|
|
|
|
nl_wait_for_ack(sock);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-09-14 18:05:03 +02:00
|
|
|
/* Check result */
|
2015-10-13 10:12:35 +02:00
|
|
|
if (!route || rtnl_route_get_nnexthops(route) != 1) {
|
|
|
|
ret = -1;
|
|
|
|
goto out2;
|
2015-09-14 18:05:03 +02:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-10-13 10:12:35 +02:00
|
|
|
ret = rtnl_route_nh_get_ifindex(rtnl_route_nexthop_n(route, 0));
|
|
|
|
|
|
|
|
rtnl_route_put(route);
|
|
|
|
|
2017-05-05 19:24:16 +00:00
|
|
|
out2: nl_cb_put(cb);
|
2015-10-13 10:12:35 +02:00
|
|
|
out: nlmsg_free(msg);
|
|
|
|
|
|
|
|
return ret;
|
2015-08-22 17:42:02 +02:00
|
|
|
}
|