usnic: helper routines for rtnetlink route lookups
Querying the OS routing table is important for making decisions about which local and remote interfaces should be paired into reliable communication channels. Reviewed-by: Jeff Squyres <jsquyres@cisco.com> cmr=v1.7.5:ticket=trac:4253 This commit was SVN r30848. The following Trac tickets were found above: Ticket 4253 --> https://svn.open-mpi.org/trac/ompi/ticket/4253
Этот коммит содержится в:
родитель
db14c706ce
Коммит
47148ab3cb
@ -31,6 +31,17 @@ test_sources = \
|
||||
test/btl_usnic_component_test.h \
|
||||
test/btl_usnic_graph_test.h
|
||||
|
||||
libnl_utils_sources = \
|
||||
btl_usnic_libnl_utils.h
|
||||
|
||||
if OMPI_BTL_USNIC_BUILD_LIBNL1_UTILS
|
||||
libnl_utils_sources += btl_usnic_libnl1_utils.c
|
||||
endif OMPI_BTL_USNIC_BUILD_LIBNL1_UTILS
|
||||
|
||||
if OMPI_BTL_USNIC_BUILD_LIBNL3_UTILS
|
||||
libnl_utils_sources += btl_usnic_libnl3_utils.c
|
||||
endif OMPI_BTL_USNIC_BUILD_LIBNL3_UTILS
|
||||
|
||||
sources = \
|
||||
btl_usnic_compat.h \
|
||||
btl_usnic_module.c \
|
||||
@ -59,7 +70,8 @@ sources = \
|
||||
btl_usnic_util.h \
|
||||
btl_usnic_test.c \
|
||||
btl_usnic_test.h \
|
||||
$(test_sources)
|
||||
$(test_sources) \
|
||||
$(libnl_utils_sources)
|
||||
|
||||
if OPAL_HAVE_HWLOC
|
||||
sources += btl_usnic_hwloc.c
|
||||
|
302
ompi/mca/btl/usnic/btl_usnic_libnl1_utils.c
Обычный файл
302
ompi/mca/btl/usnic/btl_usnic_libnl1_utils.c
Обычный файл
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cisco Systems, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/* This code is derived from similar code in libusnic_verbs. Consider porting
|
||||
* any future bug fixes from that code to this code. The original version of
|
||||
* this code was written by Xuyang Wang @ Cisco.
|
||||
*/
|
||||
|
||||
#include "ompi_config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/addr.h>
|
||||
#include <netlink/route/rtnl.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#include <netlink/route/neighbour.h>
|
||||
#include <netlink/route/neightbl.h>
|
||||
#include <netlink/route/route.h>
|
||||
|
||||
#include "btl_usnic.h"
|
||||
#include "btl_usnic_compat.h"
|
||||
|
||||
#include "btl_usnic_libnl_utils.h"
|
||||
|
||||
|
||||
/* minimize divergence from the libusnic_verbs version of this code */
|
||||
#define WANT_DEBUG_MSGS 0
|
||||
#define usnic_err(...) opal_output_verbose(20, USNIC_OUT, __VA_ARGS__)
|
||||
#define usnic_rtnl_sk_alloc ompi_btl_usnic_rtnl_sk_alloc
|
||||
#define usnic_rtnl_sk_free ompi_btl_usnic_rtnl_sk_free
|
||||
|
||||
struct usnic_rtnl_sk {
|
||||
struct nl_handle *nlh;
|
||||
uint32_t seq;
|
||||
};
|
||||
|
||||
struct nl_lookup_arg {
|
||||
uint32_t nh_addr;
|
||||
int found;
|
||||
int replied;
|
||||
int msg_count;
|
||||
int metric;
|
||||
struct usnic_rtnl_sk *unlsk;
|
||||
};
|
||||
|
||||
static struct nla_policy route_policy[RTA_MAX+1];
|
||||
|
||||
/* *sigh* use a helper routine to initialize this structure array b/c OMPI v1.6
|
||||
* demands C89, which does not support the designated initializers used in the
|
||||
* original code */
|
||||
static void init_route_policy(struct nla_policy *policy)
|
||||
{
|
||||
policy[RTA_IIF].type = NLA_STRING;
|
||||
policy[RTA_IIF].maxlen = IFNAMSIZ;
|
||||
policy[RTA_OIF].type = NLA_U32;
|
||||
policy[RTA_PRIORITY].type = NLA_U32;
|
||||
policy[RTA_FLOW].type = NLA_U32;
|
||||
policy[RTA_MP_ALGO].type = NLA_U32;
|
||||
policy[RTA_CACHEINFO].minlen = sizeof(struct rta_cacheinfo);
|
||||
policy[RTA_METRICS].type = NLA_NESTED;
|
||||
policy[RTA_MULTIPATH].type = NLA_NESTED;
|
||||
}
|
||||
|
||||
static int rtnl_raw_parse_cb(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nl_lookup_arg *lookup_arg = (struct nl_lookup_arg *)arg;
|
||||
struct usnic_rtnl_sk *unlsk = lookup_arg->unlsk;
|
||||
struct nlmsghdr *nlm_hdr = nlmsg_hdr(msg);
|
||||
struct rtmsg *rtm;
|
||||
struct nlattr *tb[RTA_MAX + 1];
|
||||
int found = 0;
|
||||
int err;
|
||||
|
||||
#if WANT_DEBUG_MSGS
|
||||
nl_msg_dump(msg, stderr);
|
||||
#endif /* WANT_DEBUG_MSGS */
|
||||
|
||||
lookup_arg->nh_addr = 0;
|
||||
lookup_arg->found = 0;
|
||||
lookup_arg->replied = 0;
|
||||
lookup_arg->msg_count++;
|
||||
|
||||
if (nlm_hdr->nlmsg_pid != nl_socket_get_local_port(unlsk->nlh)
|
||||
|| nlm_hdr->nlmsg_seq != unlsk->seq) {
|
||||
usnic_err("Not an expected reply msg pid: %u local pid: %u "
|
||||
"msg seq: %u expected seq: %u\n",
|
||||
nlm_hdr->nlmsg_pid, nl_socket_get_local_port(unlsk->nlh),
|
||||
nlm_hdr->nlmsg_seq, unlsk->seq);
|
||||
return NL_SKIP;
|
||||
}
|
||||
lookup_arg->replied = 1;
|
||||
|
||||
if (nlm_hdr->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *e = (struct nlmsgerr *)nlmsg_data(nlm_hdr);
|
||||
if (nlm_hdr->nlmsg_len >= (__u32)nlmsg_msg_size(sizeof(*e))) {
|
||||
usnic_err("Received a netlink error message %d\n",
|
||||
e->error);
|
||||
}
|
||||
else {
|
||||
usnic_err("Received a truncated netlink error message\n");
|
||||
}
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
if (nlm_hdr->nlmsg_type != RTM_NEWROUTE) {
|
||||
usnic_err("Received an invalid route request reply message\n");
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
rtm = nlmsg_data(nlm_hdr);
|
||||
if (rtm->rtm_family != AF_INET) {
|
||||
usnic_err("RTM message contains invalid AF family\n");
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
init_route_policy(route_policy);
|
||||
err = nlmsg_parse(nlm_hdr, sizeof(struct rtmsg), tb, RTA_MAX,
|
||||
route_policy);
|
||||
if (err < 0) {
|
||||
usnic_err("nlmsg parse error %d\n", err);
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
if (tb[RTA_METRICS]) {
|
||||
lookup_arg->metric = (int)nla_get_u32(tb[RTA_METRICS]);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found && tb[RTA_GATEWAY])
|
||||
lookup_arg->nh_addr = nla_get_u32(tb[RTA_GATEWAY]);
|
||||
|
||||
lookup_arg->found = found;
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int rtnl_send_ack_disable(struct usnic_rtnl_sk *unlsk, struct nl_msg *msg)
|
||||
{
|
||||
struct nlmsghdr *nlhdr;
|
||||
|
||||
nlhdr = nlmsg_hdr(msg);
|
||||
nlhdr->nlmsg_pid = nl_socket_get_local_port(unlsk->nlh);
|
||||
nlhdr->nlmsg_seq = ++unlsk->seq;
|
||||
nlmsg_set_proto(msg, NETLINK_ROUTE);
|
||||
|
||||
nlhdr->nlmsg_flags |= NLM_F_REQUEST;
|
||||
|
||||
return nl_send(unlsk->nlh, msg);
|
||||
}
|
||||
|
||||
static int nl_set_recv_timeout(struct nl_handle *handle)
|
||||
{
|
||||
int err = 0;
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
err = setsockopt(nl_socket_get_fd(handle), SOL_SOCKET, SO_RCVTIMEO,
|
||||
(char *)&timeout, sizeof(timeout));
|
||||
if (err < 0)
|
||||
usnic_err("Failed to set SO_RCVTIMEO socket option for nl socket, err %d\n",
|
||||
err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ompi_btl_usnic_nl_ip_rt_lookup(struct usnic_rtnl_sk *unlsk, uint32_t src_addr,
|
||||
uint32_t dst_addr, int *metric)
|
||||
{
|
||||
struct nl_msg *nlm;
|
||||
struct rtmsg rmsg;
|
||||
struct nl_lookup_arg arg;
|
||||
int msg_cnt;
|
||||
int err;
|
||||
|
||||
arg.nh_addr = 0;
|
||||
arg.found = 0;
|
||||
arg.replied = 0;
|
||||
arg.unlsk = unlsk;
|
||||
arg.msg_count = msg_cnt = 0;
|
||||
|
||||
memset(&rmsg, 0, sizeof(rmsg));
|
||||
rmsg.rtm_family = AF_INET;
|
||||
rmsg.rtm_dst_len = sizeof(dst_addr)*8;
|
||||
rmsg.rtm_src_len = sizeof(src_addr)*8;
|
||||
|
||||
nlm = nlmsg_alloc_simple(RTM_GETROUTE, 0);
|
||||
nlmsg_append(nlm, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
|
||||
nla_put_u32(nlm, RTA_DST, dst_addr);
|
||||
nla_put_u32(nlm, RTA_SRC, src_addr);
|
||||
|
||||
err = rtnl_send_ack_disable(unlsk, nlm);
|
||||
nlmsg_free(nlm);
|
||||
if (err < 0) {
|
||||
usnic_err("Failed to send nl route message to kernel, "
|
||||
"error %s\n", nl_geterror());
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nl_socket_modify_cb(unlsk->nlh, NL_CB_MSG_IN, NL_CB_CUSTOM,
|
||||
rtnl_raw_parse_cb, &arg);
|
||||
if (err != 0) {
|
||||
usnic_err("Failed to setup callback function, error %s\n", nl_geterror());
|
||||
return err;
|
||||
}
|
||||
|
||||
while (!arg.replied) {
|
||||
err = nl_recvmsgs_default(unlsk->nlh);
|
||||
if (err < 0) {
|
||||
usnic_err("Failed to receive nl route message from "
|
||||
"kernel, error %s\n", nl_geterror());
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* the return value of nl_recvmsgs_default does not tell
|
||||
* whether it returns because of successful read or socket
|
||||
* timeout. So we compare msg count before and after the call
|
||||
* to decide if no new message arrives. In such case,
|
||||
* this function needs to terminate to prevent the caller from
|
||||
* blocking forever
|
||||
* NL_CB_MSG_IN traps every received message, so
|
||||
* there should be no premature exit
|
||||
*/
|
||||
if (msg_cnt != arg.msg_count)
|
||||
msg_cnt = arg.msg_count;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (arg.found) {
|
||||
if (metric != NULL) {
|
||||
*metric = arg.metric;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int usnic_rtnl_sk_alloc(struct usnic_rtnl_sk **p_sk)
|
||||
{
|
||||
struct usnic_rtnl_sk *unlsk;
|
||||
struct nl_handle *nlh;
|
||||
int err;
|
||||
|
||||
unlsk = calloc(1, sizeof(*unlsk));
|
||||
if (!unlsk) {
|
||||
usnic_err("Failed to allocate usnic_rtnl_sk struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nlh = nl_handle_alloc();
|
||||
if (!nlh) {
|
||||
usnic_err("Failed to allocate nl handle\n");
|
||||
err = -ENOMEM;
|
||||
goto err_free_unlsk;
|
||||
}
|
||||
|
||||
err = nl_connect(nlh, NETLINK_ROUTE);
|
||||
if (err < 0) {
|
||||
usnic_err("Failed to connnect netlink route socket\n");
|
||||
goto err_free_nlh;
|
||||
}
|
||||
|
||||
nl_disable_sequence_check(nlh);
|
||||
err = nl_set_recv_timeout(nlh);
|
||||
if (err < 0)
|
||||
goto err_close_nlh;
|
||||
|
||||
unlsk->nlh = nlh;
|
||||
unlsk->seq = time(NULL);
|
||||
*p_sk = unlsk;
|
||||
return 0;
|
||||
|
||||
err_close_nlh:
|
||||
nl_close(nlh);
|
||||
err_free_nlh:
|
||||
nl_handle_destroy(nlh);
|
||||
err_free_unlsk:
|
||||
free(unlsk);
|
||||
return err;
|
||||
}
|
||||
|
||||
void usnic_rtnl_sk_free(struct usnic_rtnl_sk* u_nlsk)
|
||||
{
|
||||
if (u_nlsk != NULL) {
|
||||
nl_close(u_nlsk->nlh);
|
||||
nl_handle_destroy(u_nlsk->nlh);
|
||||
free(u_nlsk);
|
||||
}
|
||||
}
|
286
ompi/mca/btl/usnic/btl_usnic_libnl3_utils.c
Обычный файл
286
ompi/mca/btl/usnic/btl_usnic_libnl3_utils.c
Обычный файл
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cisco Systems, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/* This code is derived from similar code in libusnic_verbs. Consider porting
|
||||
* any future bug fixes from that code to this code. The original version of
|
||||
* this code was written by Xuyang Wang @ Cisco.
|
||||
*/
|
||||
|
||||
#include "ompi_config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* the netlink headers have many C99-isms that cause warnings on the v1.6
|
||||
* branch when --enable-picky is passed to configure :( */
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/utils.h>
|
||||
#include <netlink/addr.h>
|
||||
#include <netlink/route/rtnl.h>
|
||||
#include <netlink/route/nexthop.h>
|
||||
#include <netlink/route/route.h>
|
||||
|
||||
#include "btl_usnic.h"
|
||||
#include "btl_usnic_compat.h"
|
||||
|
||||
#include "btl_usnic_libnl_utils.h"
|
||||
|
||||
/* minimize divergence from the libusnic_verbs version of this code */
|
||||
#define WANT_DEBUG_MSGS 0
|
||||
#define usnic_err(...) opal_output_verbose(20, USNIC_OUT, __VA_ARGS__)
|
||||
#define usnic_rtnl_sk_alloc ompi_btl_usnic_rtnl_sk_alloc
|
||||
#define usnic_rtnl_sk_free ompi_btl_usnic_rtnl_sk_free
|
||||
|
||||
struct usnic_rtnl_sk {
|
||||
struct nl_sock *sock;
|
||||
uint32_t seq;
|
||||
};
|
||||
|
||||
struct nl_lookup_arg {
|
||||
uint32_t nh_addr;
|
||||
int found;
|
||||
int replied;
|
||||
int msg_count;
|
||||
int metric;
|
||||
struct usnic_rtnl_sk *unlsk;
|
||||
};
|
||||
|
||||
static struct nla_policy route_policy[RTA_MAX+1];
|
||||
|
||||
/* *sigh* use a helper routine to initialize this structure array b/c OMPI v1.6
|
||||
* demands C89, which does not support the designated initializers used in the
|
||||
* original code */
|
||||
static void init_route_policy(struct nla_policy *policy)
|
||||
{
|
||||
policy[RTA_IIF].type = NLA_STRING;
|
||||
policy[RTA_IIF].maxlen = IFNAMSIZ;
|
||||
policy[RTA_OIF].type = NLA_U32;
|
||||
policy[RTA_PRIORITY].type = NLA_U32;
|
||||
policy[RTA_FLOW].type = NLA_U32;
|
||||
policy[RTA_MP_ALGO].type = NLA_U32;
|
||||
policy[RTA_CACHEINFO].minlen = sizeof(struct rta_cacheinfo);
|
||||
policy[RTA_METRICS].type = NLA_NESTED;
|
||||
policy[RTA_MULTIPATH].type = NLA_NESTED;
|
||||
}
|
||||
|
||||
static int rtnl_raw_parse_cb(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nl_lookup_arg *lookup_arg = (struct nl_lookup_arg *)arg;
|
||||
struct usnic_rtnl_sk *unlsk = lookup_arg->unlsk;
|
||||
struct nlmsghdr *nlm_hdr = nlmsg_hdr(msg);
|
||||
struct rtmsg *rtm;
|
||||
struct nlattr *tb[RTA_MAX + 1];
|
||||
int found = 0;
|
||||
int err;
|
||||
|
||||
#if WANT_DEBUG_MSGS
|
||||
nl_msg_dump(msg, stderr);
|
||||
#endif /* WANT_DEBUG_MSGS */
|
||||
|
||||
lookup_arg->nh_addr = 0;
|
||||
lookup_arg->found = 0;
|
||||
lookup_arg->replied = 0;
|
||||
|
||||
if (nlm_hdr->nlmsg_pid != nl_socket_get_local_port(unlsk->sock)
|
||||
|| nlm_hdr->nlmsg_seq != unlsk->seq) {
|
||||
usnic_err("Not an expected reply msg pid: %u local pid: %u "
|
||||
"msg seq: %u expected seq: %u\n",
|
||||
nlm_hdr->nlmsg_pid, nl_socket_get_local_port(unlsk->sock),
|
||||
nlm_hdr->nlmsg_seq, unlsk->seq);
|
||||
return NL_SKIP;
|
||||
}
|
||||
lookup_arg->replied = 1;
|
||||
|
||||
if (nlm_hdr->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *e = (struct nlmsgerr *)nlmsg_data(nlm_hdr);
|
||||
if (nlm_hdr->nlmsg_len >= (__u32)nlmsg_size(sizeof(*e))) {
|
||||
usnic_err("Received a netlink error message %d\n",
|
||||
e->error);
|
||||
}
|
||||
else {
|
||||
usnic_err("Received a truncated netlink error message\n");
|
||||
}
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
if (nlm_hdr->nlmsg_type != RTM_NEWROUTE) {
|
||||
usnic_err("Received an invalid route request reply message\n");
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
rtm = nlmsg_data(nlm_hdr);
|
||||
if (rtm->rtm_family != AF_INET) {
|
||||
usnic_err("RTM message contains invalid AF family\n");
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
init_route_policy(route_policy);
|
||||
err = nlmsg_parse(nlm_hdr, sizeof(struct rtmsg), tb, RTA_MAX,
|
||||
route_policy);
|
||||
if (err < 0) {
|
||||
usnic_err("nlmsg parse error %d\n", err);
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
if (tb[RTA_METRICS]) {
|
||||
lookup_arg->metric = (int)nla_get_u32(tb[RTA_METRICS]);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found && tb[RTA_GATEWAY])
|
||||
lookup_arg->nh_addr = nla_get_u32(tb[RTA_GATEWAY]);
|
||||
|
||||
lookup_arg->found = found;
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int rtnl_send_ack_disable(struct usnic_rtnl_sk *unlsk, struct nl_msg *msg)
|
||||
{
|
||||
struct nlmsghdr *nlhdr;
|
||||
|
||||
nlhdr = nlmsg_hdr(msg);
|
||||
nlhdr->nlmsg_pid = nl_socket_get_local_port(unlsk->sock);
|
||||
nlhdr->nlmsg_seq = ++unlsk->seq;
|
||||
nlmsg_set_proto(msg, NETLINK_ROUTE);
|
||||
|
||||
nlhdr->nlmsg_flags |= NLM_F_REQUEST;
|
||||
|
||||
return nl_send(unlsk->sock, msg);
|
||||
}
|
||||
|
||||
static int nl_set_recv_timeout(struct nl_sock *sock)
|
||||
{
|
||||
int err = 0;
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
err = setsockopt(nl_socket_get_fd(sock), SOL_SOCKET, SO_RCVTIMEO,
|
||||
(char *)&timeout, sizeof(timeout));
|
||||
if (err < 0)
|
||||
usnic_err("Failed to set SO_RCVTIMEO socket option for nl socket, err %d\n",
|
||||
err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ompi_btl_usnic_nl_ip_rt_lookup(struct usnic_rtnl_sk *unlsk, uint32_t src_addr,
|
||||
uint32_t dst_addr, int *metric)
|
||||
{
|
||||
struct nl_msg *nlm;
|
||||
struct rtmsg rmsg;
|
||||
struct nl_lookup_arg arg;
|
||||
int msg_cnt;
|
||||
int err;
|
||||
|
||||
arg.nh_addr = 0;
|
||||
arg.found = 0;
|
||||
arg.replied = 0;
|
||||
arg.unlsk = unlsk;
|
||||
arg.msg_count = msg_cnt = 0;
|
||||
|
||||
memset(&rmsg, 0, sizeof(rmsg));
|
||||
rmsg.rtm_family = AF_INET;
|
||||
rmsg.rtm_dst_len = sizeof(dst_addr)*8;
|
||||
rmsg.rtm_src_len = sizeof(src_addr)*8;
|
||||
|
||||
nlm = nlmsg_alloc_simple(RTM_GETROUTE, 0);
|
||||
nlmsg_append(nlm, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
|
||||
nla_put_u32(nlm, RTA_DST, dst_addr);
|
||||
nla_put_u32(nlm, RTA_SRC, src_addr);
|
||||
|
||||
err = rtnl_send_ack_disable(unlsk, nlm);
|
||||
nlmsg_free(nlm);
|
||||
if (err < 0) {
|
||||
usnic_err("Failed to send rtnl query %s\n", nl_geterror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nl_socket_modify_cb(unlsk->sock, NL_CB_MSG_IN, NL_CB_CUSTOM,
|
||||
rtnl_raw_parse_cb, &arg);
|
||||
if (err != 0) {
|
||||
usnic_err("Failed to setup callback function, error %s\n",
|
||||
nl_geterror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
while (!arg.replied) {
|
||||
err = nl_recvmsgs_default(unlsk->sock);
|
||||
if (err < 0) {
|
||||
/* err will be returned as -NLE_AGAIN if the socket times out */
|
||||
usnic_err("Failed to receive rtnl query results %s\n",
|
||||
nl_geterror(err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.found) {
|
||||
if (metric != NULL) {
|
||||
*metric = arg.metric;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ompi_btl_usnic_rtnl_sk_alloc(struct usnic_rtnl_sk **p_sk)
|
||||
{
|
||||
struct usnic_rtnl_sk *unlsk;
|
||||
struct nl_sock *sock;
|
||||
int err;
|
||||
|
||||
unlsk = calloc(1, sizeof(*unlsk));
|
||||
if (!unlsk) {
|
||||
usnic_err("Failed to allocate usnic_rtnl_sk struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sock = nl_socket_alloc();
|
||||
if (!sock) {
|
||||
usnic_err("Failed to allocate nl socket\n");
|
||||
err = -ENOMEM;
|
||||
goto err_free_unlsk;
|
||||
}
|
||||
|
||||
err = nl_connect(sock, NETLINK_ROUTE);
|
||||
if (err < 0) {
|
||||
usnic_err("Failed to connnect netlink route socket\n");
|
||||
goto err_free_sk;
|
||||
}
|
||||
|
||||
nl_socket_disable_seq_check(sock);
|
||||
err = nl_set_recv_timeout(sock);
|
||||
if (err < 0)
|
||||
goto err_close_nlsk;
|
||||
|
||||
unlsk->sock = sock;
|
||||
unlsk->seq = time(NULL);
|
||||
*p_sk = unlsk;
|
||||
return 0;
|
||||
|
||||
err_close_nlsk:
|
||||
nl_close(sock);
|
||||
err_free_sk:
|
||||
nl_socket_free(sock);
|
||||
err_free_unlsk:
|
||||
free(unlsk);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ompi_btl_usnic_rtnl_sk_free(struct usnic_rtnl_sk *unlsk)
|
||||
{
|
||||
if (unlsk != NULL) {
|
||||
nl_close(unlsk->sock);
|
||||
nl_socket_free(unlsk->sock);
|
||||
free(unlsk);
|
||||
}
|
||||
}
|
36
ompi/mca/btl/usnic/btl_usnic_libnl_utils.h
Обычный файл
36
ompi/mca/btl/usnic/btl_usnic_libnl_utils.h
Обычный файл
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Cisco Systems, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef LIBNL_UTILS_H
|
||||
#define LIBNL_UTILS_H
|
||||
|
||||
/* This header file and btl_usnic_libnl1_utils.c/btl_usnic_libnl3_utils.c are
|
||||
* here to support OS routing lookups. They use the Linux "routing netlink"
|
||||
* communication subsystem (see "man 7 rtnetlink") via the "libnl" helper
|
||||
* library. Unfortunately, libnl comes in two major versions: libnl (v1) and
|
||||
* libnl-3 with significant API differences between them.
|
||||
*
|
||||
* Quick glossary to some of the abbreviations here:
|
||||
* rtnl -- rtnetlink (routing netlink)
|
||||
* sk -- socket
|
||||
*/
|
||||
|
||||
struct usnic_rtnl_sk;
|
||||
|
||||
/* returns zero on success or negative errno values on failure */
|
||||
int ompi_btl_usnic_rtnl_sk_alloc(struct usnic_rtnl_sk **p_sk);
|
||||
|
||||
void ompi_btl_usnic_rtnl_sk_free(struct usnic_rtnl_sk* u_nlsk);
|
||||
|
||||
/* src_addr and dst_addr are IPv4 addresses in network byte order. Returns
|
||||
* zero on successful route lookup, -1 otherwise. */
|
||||
int ompi_btl_usnic_nl_ip_rt_lookup(struct usnic_rtnl_sk *unlsk, uint32_t src_addr,
|
||||
uint32_t dst_addr, int *metric);
|
||||
|
||||
#endif /* LIBNL_UTILS_H */
|
@ -101,6 +101,10 @@ AC_DEFUN([OMPI_CHECK_LIBNL3],[
|
||||
AC_DEFUN([MCA_ompi_btl_usnic_POST_CONFIG], [
|
||||
AM_CONDITIONAL([OMPI_BTL_USNIC_BUILD_UNIT_TESTS],
|
||||
[test "$1" -eq 1 && test "X$enable_ompi_btl_usnic_unit_tests" = "Xyes"])
|
||||
AM_CONDITIONAL([OMPI_BTL_USNIC_BUILD_LIBNL1_UTILS],
|
||||
[test "$1" -eq 1 && test "X$enable_ompi_btl_usnic_libnl1_utils" = "Xyes"])
|
||||
AM_CONDITIONAL([OMPI_BTL_USNIC_BUILD_LIBNL3_UTILS],
|
||||
[test "$1" -eq 1 && test "X$enable_ompi_btl_usnic_libnl3_utils" = "Xyes"])
|
||||
])
|
||||
|
||||
# MCA_btl_usnic_CONFIG([action-if-can-compile],
|
||||
@ -152,6 +156,38 @@ AC_DEFUN([MCA_ompi_btl_usnic_CONFIG],[
|
||||
]
|
||||
)
|
||||
|
||||
# Search for libnl so we can query routing information. We need to
|
||||
# distinguish between v1 and v3.
|
||||
enable_ompi_btl_usnic_libnl1_utils=no
|
||||
enable_ompi_btl_usnic_libnl3_utils=no
|
||||
AS_IF([test "$btl_usnic_happy" = "yes"],
|
||||
[OMPI_CHECK_LIBNL3([btl_usnic_libnl],
|
||||
[enable_ompi_btl_usnic_libnl3_utils=yes],
|
||||
[enable_ompi_btl_usnic_libnl3_utils=no])
|
||||
|
||||
# fall back to libnl1 if libnl3 could not be found
|
||||
AS_IF([test "X$enable_ompi_btl_usnic_libnl3_utils" = "Xno"],
|
||||
[OMPI_CHECK_PACKAGE([btl_usnic_libnl],
|
||||
[netlink/netlink.h],
|
||||
[nl],
|
||||
[nl_recvmsgs_default],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[enable_ompi_btl_usnic_libnl1_utils=yes],
|
||||
[enable_ompi_btl_usnic_libnl1_utils=no])])
|
||||
|
||||
AS_IF([test "X$enable_ompi_btl_usnic_libnl3_utils" = "Xno" &&
|
||||
test "X$enable_ompi_btl_usnic_libnl1_utils" = "Xno"],
|
||||
[AC_MSG_NOTICE([could not find a libnl or libnl-3, disabling the usnic BTL])
|
||||
btl_usnic_happy="no"])
|
||||
|
||||
btl_usnic_CPPFLAGS="$btl_usnic_CPPFLAGS $btl_usnic_libnl_CPPFLAGS"
|
||||
btl_usnic_CFLAGS="$btl_usnic_CFLAGS $btl_usnic_libnl_CFLAGS"
|
||||
btl_usnic_LDFLAGS="$btl_usnic_LDFLAGS $btl_usnic_libnl_LDFLAGS"
|
||||
btl_usnic_LIBS="$btl_usnic_libnl_LIBS $btl_usnic_LIBS"
|
||||
])
|
||||
|
||||
AS_IF([test "$btl_usnic_happy" = "yes"],
|
||||
[btl_usnic_WRAPPER_EXTRA_LDFLAGS="$btl_usnic_LDFLAGS"
|
||||
btl_usnic_WRAPPER_EXTRA_LIBS="$btl_usnic_LIBS"
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user