@@ -838,6 +838,9 @@ struct lnet_inetdev {
int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns,
bool v6);
+int lnet_inet_select(struct lnet_ni *ni, struct lnet_inetdev *ifaces,
+ int num_ifaces);
+
void lnet_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize);
void lnet_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize);
int lnet_sock_getaddr(struct socket *socket, bool remote,
@@ -90,11 +90,6 @@ static inline __u32 LNET_NIDNET(lnet_nid_t nid)
return (nid >> 32) & 0xffffffff;
}
-static inline lnet_nid_t LNET_MKNID(__u32 net, __u32 addr)
-{
- return (((__u64)net) << 32) | addr;
-}
-
static inline __u32 LNET_NETNUM(__u32 net)
{
return net & 0xffff;
@@ -110,25 +105,41 @@ static inline __u32 LNET_MKNET(__u32 type, __u32 num)
return (type << 16) | num;
}
+static inline lnet_nid_t LNET_MKNID(__u32 net, __u32 addr)
+{
+ return (((__u64)net) << 32) | addr;
+}
+
/** The lolnd NID (i.e. myself) */
#define LNET_NID_LO_0 LNET_MKNID(LNET_MKNET(LOLND, 0), 0)
#define LNET_NET_ANY LNET_NIDNET(LNET_NID_ANY)
-/* check for address set */
-static inline bool nid_addr_is_set(const struct lnet_nid *nid)
+static inline bool nid_is_nid4(const struct lnet_nid *nid)
{
- int sum = 0, i;
+ return NID_ADDR_BYTES(nid) == 4;
+}
- for (i = 0; i < NID_ADDR_BYTES(nid); i++)
- sum |= nid->nid_addr[i];
+static inline bool nid_is_ipv4(const struct lnet_nid *nid)
+{
+ return NID_ADDR_BYTES(nid) == 4;
+}
- return sum ? true : false;
+static inline bool nid_is_ipv6(const struct lnet_nid *nid)
+{
+ return NID_ADDR_BYTES(nid) == 16;
}
-static inline int nid_is_nid4(const struct lnet_nid *nid)
+/* check for address set */
+static inline bool nid_addr_is_set(const struct lnet_nid *nid)
{
- return NID_ADDR_BYTES(nid) == 4;
+ int i;
+
+ for (i = 0; i < NID_ADDR_BYTES(nid); i++)
+ if (nid->nid_addr[i])
+ return true;
+
+ return false;
}
/* LOLND may not be defined yet, so we cannot use an inline */
@@ -2542,8 +2542,7 @@ ksocknal_startup(struct lnet_ni *ni)
struct ksock_net *net;
struct ksock_interface *ksi = NULL;
struct lnet_inetdev *ifaces = NULL;
- int i = 0;
- int rc;
+ int rc, if_idx;
LASSERT(ni->ni_net->net_lnd == &the_ksocklnd);
@@ -2555,7 +2554,7 @@ ksocknal_startup(struct lnet_ni *ni)
net = kzalloc(sizeof(*net), GFP_NOFS);
if (!net)
- goto fail_0;
+ goto out_base;
net->ksnn_incarnation = ktime_get_real_ns();
ni->ni_data = net;
@@ -2564,55 +2563,51 @@ ksocknal_startup(struct lnet_ni *ni)
rc = lnet_inet_enumerate(&ifaces, ni->ni_net_ns, true);
if (rc < 0)
- goto fail_1;
+ goto out_net;
ksi = &net->ksnn_interface;
- /* Use the first discovered interface or look in the list */
- if (ni->ni_interface) {
- for (i = 0; i < rc; i++) {
- if (strcmp(ifaces[i].li_name, ni->ni_interface) == 0)
- break;
- }
- /* ni_interface doesn't contain the interface we want */
- if (i == rc) {
- CERROR("ksocklnd: failed to find interface %s\n",
- ni->ni_interface);
- goto fail_1;
- }
- } else {
- rc = lnet_ni_add_interface(ni, ifaces[i].li_name);
+
+ /* Interface and/or IP address is specified otherwise default to
+ * the first Interface
+ */
+ if_idx = lnet_inet_select(ni, ifaces, rc);
+ if (if_idx < 0)
+ goto out_net;
+
+ if (!ni->ni_interface) {
+ rc = lnet_ni_add_interface(ni, ifaces[if_idx].li_name);
if (rc < 0)
CWARN("ksocklnd failed to allocate ni_interface\n");
}
- ni->ni_dev_cpt = ifaces[i].li_cpt;
- ksi->ksni_index = ifaces[i].li_index;
- if (ifaces[i].li_ipv6) {
+ ni->ni_dev_cpt = ifaces[if_idx].li_cpt;
+ ksi->ksni_index = ifaces[if_idx].li_index;
+ if (ifaces[if_idx].li_ipv6) {
struct sockaddr_in6 *sa;
sa = (void *)&ksi->ksni_addr;
memset(sa, 0, sizeof(*sa));
sa->sin6_family = AF_INET6;
- memcpy(&sa->sin6_addr, ifaces[i].li_ipv6addr,
+ memcpy(&sa->sin6_addr, ifaces[if_idx].li_ipv6addr,
sizeof(struct in6_addr));
ni->ni_nid.nid_size = sizeof(struct in6_addr) - 4;
- memcpy(&ni->ni_nid.nid_addr, ifaces[i].li_ipv6addr,
+ memcpy(&ni->ni_nid.nid_addr, ifaces[if_idx].li_ipv6addr,
sizeof(struct in6_addr));
} else {
struct sockaddr_in *sa;
sa = (void *)&ksi->ksni_addr;
memset(sa, 0, sizeof(*sa));
sa->sin_family = AF_INET;
- sa->sin_addr.s_addr = htonl(ifaces[i].li_ipaddr);
- ksi->ksni_netmask = ifaces[i].li_netmask;
+ sa->sin_addr.s_addr = htonl(ifaces[if_idx].li_ipaddr);
+ ksi->ksni_netmask = ifaces[if_idx].li_netmask;
ni->ni_nid.nid_size = 4 - 4;
ni->ni_nid.nid_addr[0] = sa->sin_addr.s_addr;
}
- strlcpy(ksi->ksni_name, ifaces[i].li_name, sizeof(ksi->ksni_name));
+ strlcpy(ksi->ksni_name, ifaces[if_idx].li_name, sizeof(ksi->ksni_name));
/* call it before add it to ksocknal_data.ksnd_nets */
rc = ksocknal_net_start_threads(net, ni->ni_cpts, ni->ni_ncpts);
if (rc)
- goto fail_1;
+ goto out_net;
list_add(&net->ksnn_list, &ksocknal_data.ksnd_nets);
net->ksnn_ni = ni;
@@ -2620,9 +2615,9 @@ ksocknal_startup(struct lnet_ni *ni)
return 0;
-fail_1:
+out_net:
kfree(net);
-fail_0:
+out_base:
if (!ksocknal_data.ksnd_nnets)
ksocknal_base_shutdown();
@@ -1615,6 +1615,56 @@ int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns, bool v6)
}
EXPORT_SYMBOL(lnet_inet_enumerate);
+int lnet_inet_select(struct lnet_ni *ni,
+ struct lnet_inetdev *ifaces,
+ int num_ifaces)
+{
+ bool addr_set = nid_addr_is_set(&ni->ni_nid);
+ int if_idx;
+
+ /* default to first interface if both interface and NID unspecified */
+ if (!ni->ni_interface && !addr_set)
+ return 0;
+
+ for (if_idx = 0; if_idx < num_ifaces; if_idx++) {
+ if (ni->ni_interface &&
+ strcmp(ni->ni_interface, ifaces[if_idx].li_name) != 0)
+ /* not the specified interface */
+ continue;
+
+ if (!addr_set)
+ /* IP unspecified, use IP of first matching interface */
+ break;
+
+ if (ifaces[if_idx].li_ipv6 &&
+ nid_is_ipv6(&ni->ni_nid)) {
+ if (memcmp(ni->ni_nid.nid_addr,
+ ifaces[if_idx].li_ipv6addr,
+ sizeof(struct in6_addr)) == 0)
+ break;
+ } else if (!ifaces[if_idx].li_ipv6 &&
+ nid_is_ipv4(&ni->ni_nid)) {
+ if (ni->ni_nid.nid_addr[0] ==
+ htonl(ifaces[if_idx].li_ipaddr))
+ break;
+ }
+ }
+
+ if (if_idx < num_ifaces)
+ return if_idx;
+
+ if (ni->ni_interface)
+ CERROR("ksocklnd: failed to find interface %s%s%s\n",
+ ni->ni_interface, addr_set ? "@" : "",
+ addr_set ? libcfs_nidstr(&ni->ni_nid) : "");
+ else
+ CERROR("ksocklnd: failed to find IP address %s\n",
+ libcfs_nidstr(&ni->ni_nid));
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(lnet_inet_select);
+
int
lnet_parse_ip2nets(const char **networksp, const char *ip2nets)
{