1 //  Copyright (c) 2015 John Biddiscombe
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef HPX_PARCELSET_POLICIES_LIBFABRIC_LOCALITY_HPP
7 #define HPX_PARCELSET_POLICIES_LIBFABRIC_LOCALITY_HPP
8 
9 #include <hpx/runtime/parcelset/locality.hpp>
10 #include <hpx/runtime/serialization/serialize.hpp>
11 #include <hpx/runtime/serialization/array.hpp>
12 //
13 #include <utility>
14 #include <cstring>
15 #include <cstdint>
16 #include <array>
17 #include <rdma/fabric.h>
18 
19 // Different providers use different address formats that we must accomodate
20 // in our locality object.
21 #ifdef HPX_PARCELPORT_LIBFABRIC_GNI
22 # define HPX_PARCELPORT_LIBFABRIC_LOCALITY_SIZE 48
23 #endif
24 
25 #if defined(HPX_PARCELPORT_LIBFABRIC_VERBS) || \
26     defined(HPX_PARCELPORT_LIBFABRIC_SOCKETS) || \
27     defined(HPX_PARCELPORT_LIBFABRIC_PSM2)
28 # define HPX_PARCELPORT_LIBFABRIC_LOCALITY_SIZE 16
29 # define HPX_PARCELPORT_LIBFABRIC_LOCALITY_SOCKADDR
30 #endif
31 
32 //typedef struct fid* fi_addr_t;
33 
34 namespace hpx {
35 namespace parcelset {
36 namespace policies {
37 namespace libfabric
38 {
39 
40 // --------------------------------------------------------------------
41 // Locality, in this structure we store the informartion required by
42 // libfabric to make a connection to another node.
43 // With libfabric 1.4.x the array contains the fabric ip address stored
44 // as the second uint32_t in the array. For this reason we use an
45 // array of uint32_t rather than uint8_t/char so we can easily access
46 // the ip for debug/validation purposes
47 // --------------------------------------------------------------------
48 struct locality {
49 
50     // the number of 32bit ints stored in our array
51     static const uint32_t array_length = HPX_PARCELPORT_LIBFABRIC_LOCALITY_SIZE/4;
52     static const uint32_t array_size = HPX_PARCELPORT_LIBFABRIC_LOCALITY_SIZE;
53 
54     // array type of our locality data
55     typedef std::array<uint32_t, array_length> locality_data;
56 
typehpx::parcelset::policies::libfabric::locality57     static const char *type() {
58         return "libfabric";
59     }
60 
localityhpx::parcelset::policies::libfabric::locality61     explicit locality(const locality_data &in_data)
62     {
63         std::memcpy(&data_[0], &in_data[0], array_size);
64         fi_address_ = 0;
65         LOG_DEBUG_MSG("explicit constructing locality from "
66             << ipaddress(ip_address()) << ":" << decnumber(port()));
67     }
68 
localityhpx::parcelset::policies::libfabric::locality69     locality() {
70         std::memset(&data_[0], 0x00, array_size);
71         fi_address_ = 0;
72         LOG_DEBUG_MSG("default constructing locality from "
73             << ipaddress(ip_address()) << ":" << decnumber(port()));
74     }
75 
localityhpx::parcelset::policies::libfabric::locality76     locality(const locality &other) : data_(other.data_) {
77         fi_address_ = other.fi_address_;
78         LOG_DEBUG_MSG("copy constructing locality with "
79             << ipaddress(ip_address()) << ":" << decnumber(port()));
80     }
81 
localityhpx::parcelset::policies::libfabric::locality82     locality(locality &&other) : data_(std::move(other.data_)),
83         fi_address_(other.fi_address_)
84     {
85         LOG_DEBUG_MSG("move constructing locality with "
86             << ipaddress(ip_address()) << ":" << decnumber(port()));
87     }
88 
operator =hpx::parcelset::policies::libfabric::locality89     locality & operator = (const locality &other) {
90         data_       = other.data_;
91         fi_address_ = other.fi_address_;
92         LOG_DEBUG_MSG("copy operator locality with "
93             << ipaddress(ip_address()) << ":" << decnumber(port()));
94         return *this;
95     }
96 
ip_addresshpx::parcelset::policies::libfabric::locality97     const uint32_t & ip_address() const {
98 #if defined (HPX_PARCELPORT_LIBFABRIC_LOCALITY_SOCKADDR)
99         return reinterpret_cast<const struct sockaddr_in*>
100             (data_.data())->sin_addr.s_addr;
101 #elif defined(HPX_PARCELPORT_LIBFABRIC_GNI)
102         return data_[0];
103 #else
104         throw fabric_error(0, "unsupported fabric provider, please fix ASAP");
105 #endif
106     }
107 
ip_addresshpx::parcelset::policies::libfabric::locality108     static const uint32_t & ip_address(const locality_data &data) {
109 #if defined (HPX_PARCELPORT_LIBFABRIC_LOCALITY_SOCKADDR)
110         return reinterpret_cast<const struct sockaddr_in*>
111             (&data)->sin_addr.s_addr;
112 #elif defined(HPX_PARCELPORT_LIBFABRIC_GNI)
113         return data[0];
114 #else
115         throw fabric_error(0, "unsupported fabric provider, please fix ASAP");
116 #endif
117     }
118 
fi_addresshpx::parcelset::policies::libfabric::locality119     fi_addr_t fi_address() const {
120         return fi_address_;
121     }
122 
set_fi_addresshpx::parcelset::policies::libfabric::locality123     void set_fi_address(fi_addr_t fi_addr) {
124         fi_address_ = fi_addr;
125     }
126 
porthpx::parcelset::policies::libfabric::locality127     uint16_t port() const {
128         uint16_t port = 256*reinterpret_cast<const uint8_t*>(data_.data())[2]
129             + reinterpret_cast<const uint8_t*>(data_.data())[3];
130         return port;
131     }
132 
133     // some condition marking this locality as valid
operator boolhpx::parcelset::policies::libfabric::locality134     explicit operator bool() const {
135         return (ip_address() != 0);
136     }
137 
savehpx::parcelset::policies::libfabric::locality138     void save(serialization::output_archive & ar) const {
139         ar << data_;
140     }
141 
loadhpx::parcelset::policies::libfabric::locality142     void load(serialization::input_archive & ar) {
143         ar >> data_;
144     }
145 
fabric_datahpx::parcelset::policies::libfabric::locality146     const void *fabric_data() const { return data_.data(); }
147 
fabric_data_writablehpx::parcelset::policies::libfabric::locality148     char *fabric_data_writable() { return reinterpret_cast<char*>(data_.data()); }
149 
150 
validhpx::parcelset::policies::libfabric::locality151     bool valid() { return true; }
152 
153 private:
operator ==(locality const & lhs,locality const & rhs)154     friend bool operator==(locality const & lhs, locality const & rhs) {
155 #if defined(HPX_PARCELPORT_LIBFABRIC_HAVE_LOGGING)
156         uint32_t a1 = lhs.ip_address();
157         uint32_t a2 = rhs.ip_address();
158         LOG_DEBUG_MSG("Testing array equality "
159             << ipaddress(a1)
160             << ipaddress(a2)
161         );
162 #endif
163         return (lhs.data_ == rhs.data_);
164     }
165 
operator <(locality const & lhs,locality const & rhs)166     friend bool operator<(locality const & lhs, locality const & rhs) {
167         uint32_t a1 = lhs.ip_address();
168         uint32_t a2 = rhs.ip_address();
169         return a1 < a2;
170     }
171 
operator <<(std::ostream & os,locality const & loc)172     friend std::ostream & operator<<(std::ostream & os, locality const & loc) {
173         boost::io::ios_flags_saver ifs(os);
174         for (uint32_t i=0; i<array_length; ++i) {
175             os << loc.data_[i];
176         }
177         return os;
178     }
179 
180 private:
181     locality_data data_;
182     fi_addr_t     fi_address_;
183 };
184 
185 }}}}
186 
187 #endif
188 
189