-static int
-ksocknal_local_ipvec(struct lnet_ni *ni, __u32 *ipaddrs)
-{
- struct ksock_net *net = ni->ni_data;
- int i, j;
- int nip;
-
- read_lock(&ksocknal_data.ksnd_global_lock);
-
- nip = net->ksnn_ninterfaces;
- LASSERT(nip <= LNET_INTERFACES_NUM);
-
- for (i = 0, j = 0; i < nip; i++)
- if (net->ksnn_interfaces[i].ksni_addr.ss_family == AF_INET) {
- struct sockaddr_in *sa =
- (void *)&net->ksnn_interfaces[i].ksni_addr;
-
- ipaddrs[j] = ntohl(sa->sin_addr.s_addr);
- LASSERT(ipaddrs[j] != 0);
- j += 1;
- }
- nip = j;
-
- read_unlock(&ksocknal_data.ksnd_global_lock);
- /*
- * Only offer interfaces for additional connections if I have
- * more than one.
- */
- return nip < 2 ? 0 : nip;
-}
-
-static int
-ksocknal_match_peerip(struct ksock_interface *iface, __u32 *ips, int nips)
-{
- int best_netmatch = 0;
- int best_xor = 0;
- int best = -1;
- int this_xor;
- int this_netmatch;
- int i;
- struct sockaddr_in *sa;
- __u32 ip;
-
- sa = (struct sockaddr_in *)&iface->ksni_addr;
- LASSERT(sa->sin_family == AF_INET);
- ip = ntohl(sa->sin_addr.s_addr);
-
- for (i = 0; i < nips; i++) {
- if (ips[i] == 0)
- continue;
-
- this_xor = ips[i] ^ ip;
- this_netmatch = ((this_xor & iface->ksni_netmask) == 0) ? 1 : 0;
-
- if (!(best < 0 ||
- best_netmatch < this_netmatch ||
- (best_netmatch == this_netmatch &&
- best_xor > this_xor)))
- continue;
-
- best = i;
- best_netmatch = this_netmatch;
- best_xor = this_xor;
- }
-
- LASSERT(best >= 0);
- return best;
-}
-
-static int
-ksocknal_select_ips(struct ksock_peer_ni *peer_ni, __u32 *peerips, int n_peerips)
-{
- rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock;
- struct ksock_net *net = peer_ni->ksnp_ni->ni_data;
- struct ksock_interface *iface;
- struct ksock_interface *best_iface;
- int n_ips;
- int i;
- int j;
- int k;
- u32 ip;
- u32 xor;
- int this_netmatch;
- int best_netmatch;
- int best_npeers;
-
- /* CAVEAT EMPTOR: We do all our interface matching with an
- * exclusive hold of global lock at IRQ priority. We're only
- * expecting to be dealing with small numbers of interfaces, so the
- * O(n**3)-ness shouldn't matter */
-
- /* Also note that I'm not going to return more than n_peerips
- * interfaces, even if I have more myself */
-
- write_lock_bh(global_lock);
-
- LASSERT(n_peerips <= LNET_INTERFACES_NUM);
- LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM);
-
- /* Only match interfaces for additional connections
- * if I have > 1 interface
- */
- n_ips = (net->ksnn_ninterfaces < 2) ? 0 :
- min(n_peerips, net->ksnn_ninterfaces);
-
- for (i = 0; peer_ni->ksnp_n_passive_ips < n_ips; i++) {
- /* ^ yes really... */
-
- /* If we have any new interfaces, first tick off all the
- * peer_ni IPs that match old interfaces, then choose new
- * interfaces to match the remaining peer_ni IPS.
- * We don't forget interfaces we've stopped using; we might
- * start using them again... */
-
- if (i < peer_ni->ksnp_n_passive_ips) {
- /* Old interface. */
- struct sockaddr_in sa = { .sin_family = AF_INET};
-
- sa.sin_addr.s_addr =
- htonl(peer_ni->ksnp_passive_ips[i]);
- best_iface = ksocknal_ip2iface(peer_ni->ksnp_ni,
- (struct sockaddr *)&sa);
-
- /* peer_ni passive ips are kept up to date */
- LASSERT(best_iface != NULL);
- } else {
- /* choose a new interface */
- struct sockaddr_in *sa;
-
- LASSERT (i == peer_ni->ksnp_n_passive_ips);
-
- best_iface = NULL;
- best_netmatch = 0;
- best_npeers = 0;
-
- for (j = 0; j < net->ksnn_ninterfaces; j++) {
- iface = &net->ksnn_interfaces[j];
- sa = (void *)&iface->ksni_addr;
- if (sa->sin_family != AF_INET)
- continue;
- ip = ntohl(sa->sin_addr.s_addr);
-
- for (k = 0; k < peer_ni->ksnp_n_passive_ips; k++)
- if (peer_ni->ksnp_passive_ips[k] == ip)
- break;
-
- if (k < peer_ni->ksnp_n_passive_ips) /* using it already */
- continue;
-
- k = ksocknal_match_peerip(iface, peerips, n_peerips);
- xor = (ip ^ peerips[k]);
- this_netmatch = ((xor & iface->ksni_netmask) == 0) ? 1 : 0;
-
- if (!(best_iface == NULL ||
- best_netmatch < this_netmatch ||
- (best_netmatch == this_netmatch &&
- best_npeers > iface->ksni_npeers)))
- continue;
-
- best_iface = iface;
- best_netmatch = this_netmatch;
- best_npeers = iface->ksni_npeers;
- }
-
- LASSERT(best_iface != NULL);
-
- best_iface->ksni_npeers++;
- sa = (void *)&best_iface->ksni_addr;
- ip = ntohl(sa->sin_addr.s_addr);
- peer_ni->ksnp_passive_ips[i] = ip;
- peer_ni->ksnp_n_passive_ips = i+1;
- }
-
- /* mark the best matching peer_ni IP used */
- j = ksocknal_match_peerip(best_iface, peerips, n_peerips);
- peerips[j] = 0;
- }
-
- /* Overwrite input peer_ni IP addresses */
- memcpy(peerips, peer_ni->ksnp_passive_ips, n_ips * sizeof(*peerips));
-
- write_unlock_bh(global_lock);
-
- return (n_ips);
-}
-
-static void
-ksocknal_create_routes(struct ksock_peer_ni *peer_ni, int port,
- __u32 *peer_ipaddrs, int npeer_ipaddrs)
-{
- struct ksock_route *newroute = NULL;
- rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock;
- struct lnet_ni *ni = peer_ni->ksnp_ni;
- struct ksock_net *net = ni->ni_data;
- struct list_head *rtmp;
- struct ksock_route *route;
- struct ksock_interface *iface;
- struct ksock_interface *best_iface;
- int best_netmatch;
- int this_netmatch;
- int best_nroutes;
- int i;
- int j;
-
- /* CAVEAT EMPTOR: We do all our interface matching with an
- * exclusive hold of global lock at IRQ priority. We're only
- * expecting to be dealing with small numbers of interfaces, so the
- * O(n**3)-ness here shouldn't matter */
-
- write_lock_bh(global_lock);
-
- if (net->ksnn_ninterfaces < 2) {
- /* Only create additional connections
- * if I have > 1 interface */
- write_unlock_bh(global_lock);
- return;
- }
-
- LASSERT(npeer_ipaddrs <= LNET_INTERFACES_NUM);
-
- for (i = 0; i < npeer_ipaddrs; i++) {
- if (newroute) {
- struct sockaddr_in *sa = (void *)&newroute->ksnr_addr;
-
- memset(sa, 0, sizeof(*sa));
- sa->sin_family = AF_INET;
- sa->sin_addr.s_addr = htonl(peer_ipaddrs[i]);
- } else {
- struct sockaddr_in sa = {.sin_family = AF_INET};
-
- write_unlock_bh(global_lock);
-
- sa.sin_addr.s_addr = htonl(peer_ipaddrs[i]);
- sa.sin_port = htons(port);
- newroute =
- ksocknal_create_route((struct sockaddr *)&sa);
- if (!newroute)
- return;
-
- write_lock_bh(global_lock);
- }
-
- if (peer_ni->ksnp_closing) {
- /* peer_ni got closed under me */
- break;
- }
-
- /* Already got a route? */
- route = NULL;
- list_for_each(rtmp, &peer_ni->ksnp_routes) {
- route = list_entry(rtmp, struct ksock_route, ksnr_list);
-
- if (rpc_cmp_addr(
- (struct sockaddr *)&route->ksnr_addr,
- (struct sockaddr *)&newroute->ksnr_addr))
- break;
-
- route = NULL;
- }
- if (route != NULL)
- continue;
-
- best_iface = NULL;
- best_nroutes = 0;
- best_netmatch = 0;
-
- LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM);
-
- /* Select interface to connect from */
- for (j = 0; j < net->ksnn_ninterfaces; j++) {
- __u32 iface_ip, route_ip;
-
- iface = &net->ksnn_interfaces[j];
-
- /* Using this interface already? */
- list_for_each(rtmp, &peer_ni->ksnp_routes) {
- route = list_entry(rtmp, struct ksock_route,
- ksnr_list);
-
- if (route->ksnr_myiface == iface->ksni_index)
- break;
-
- route = NULL;
- }
- if (route != NULL)
- continue;
- if (iface->ksni_addr.ss_family != AF_INET)
- continue;
- if (newroute->ksnr_addr.ss_family != AF_INET)
- continue;
-
- iface_ip =
- ntohl(((struct sockaddr_in *)
- &iface->ksni_addr)->sin_addr.s_addr);
- route_ip =
- ntohl(((struct sockaddr_in *)
- &newroute->ksnr_addr)->sin_addr.s_addr);
-
- this_netmatch = (((iface_ip ^ route_ip) &
- iface->ksni_netmask) == 0) ? 1 : 0;
-
- if (!(best_iface == NULL ||
- best_netmatch < this_netmatch ||
- (best_netmatch == this_netmatch &&
- best_nroutes > iface->ksni_nroutes)))
- continue;
-
- best_iface = iface;
- best_netmatch = this_netmatch;
- best_nroutes = iface->ksni_nroutes;
- }
-
- if (best_iface == NULL)
- continue;
-
- newroute->ksnr_myiface = best_iface->ksni_index;
- best_iface->ksni_nroutes++;
-
- ksocknal_add_route_locked(peer_ni, newroute);
- newroute = NULL;
- }
-
- write_unlock_bh(global_lock);
- if (newroute != NULL)
- ksocknal_route_decref(newroute);
-}
-