]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2012 Inktank | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "common/pick_address.h" | |
9f95a23c TL |
16 | |
17 | #include <netdb.h> | |
522d829b | 18 | #include <netinet/in.h> |
9f95a23c TL |
19 | #include <string> |
20 | #include <string.h> | |
21 | #include <vector> | |
22 | ||
522d829b | 23 | #include <boost/algorithm/string/predicate.hpp> |
9f95a23c TL |
24 | #include <fmt/format.h> |
25 | ||
7c673cae FG |
26 | #include "include/ipaddr.h" |
27 | #include "include/str_list.h" | |
11fdf7f2 TL |
28 | #include "common/ceph_context.h" |
29 | #ifndef WITH_SEASTAR | |
30 | #include "common/config.h" | |
31 | #include "common/config_obs.h" | |
32 | #endif | |
7c673cae FG |
33 | #include "common/debug.h" |
34 | #include "common/errno.h" | |
11fdf7f2 | 35 | #include "common/numa.h" |
7c673cae | 36 | |
522d829b TL |
37 | #ifndef HAVE_IN_ADDR_T |
38 | typedef uint32_t in_addr_t; | |
39 | #endif | |
40 | ||
41 | #ifndef IN_LOOPBACKNET | |
42 | #define IN_LOOPBACKNET 127 | |
43 | #endif | |
44 | ||
7c673cae FG |
45 | #define dout_subsys ceph_subsys_ |
46 | ||
f67539c2 TL |
47 | using std::string; |
48 | using std::vector; | |
49 | ||
522d829b TL |
50 | namespace { |
51 | ||
52 | bool matches_with_name(const ifaddrs& ifa, const std::string& if_name) | |
53 | { | |
54 | return if_name.compare(ifa.ifa_name) == 0; | |
55 | } | |
56 | ||
57 | static int is_loopback_addr(sockaddr* addr) | |
58 | { | |
59 | if (addr->sa_family == AF_INET) { | |
60 | const sockaddr_in* sin = (struct sockaddr_in *)(addr); | |
61 | const in_addr_t net = ntohl(sin->sin_addr.s_addr) >> IN_CLASSA_NSHIFT; | |
62 | return net == IN_LOOPBACKNET ? 1 : 0; | |
63 | } else if (addr->sa_family == AF_INET6) { | |
64 | sockaddr_in6* sin6 = (struct sockaddr_in6 *)(addr); | |
65 | return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) ? 1 : 0; | |
66 | } else { | |
67 | return -1; | |
68 | } | |
69 | } | |
70 | ||
71 | static int grade_addr(const ifaddrs& ifa) | |
72 | { | |
73 | if (ifa.ifa_addr == nullptr) { | |
74 | return -1; | |
75 | } | |
76 | int score = 0; | |
77 | if (ifa.ifa_flags & IFF_UP) { | |
78 | score += 4; | |
79 | } | |
80 | switch (is_loopback_addr(ifa.ifa_addr)) { | |
81 | case 0: | |
82 | // prefer non-loopback addresses | |
83 | score += 2; | |
84 | break; | |
85 | case 1: | |
86 | score += 0; | |
87 | break; | |
88 | default: | |
89 | score = -1; | |
90 | break; | |
91 | } | |
92 | return score; | |
93 | } | |
94 | ||
95 | bool matches_with_net(const ifaddrs& ifa, | |
96 | const sockaddr* net, | |
97 | unsigned int prefix_len, | |
98 | unsigned ipv) | |
99 | { | |
100 | switch (net->sa_family) { | |
101 | case AF_INET: | |
102 | if (ipv & CEPH_PICK_ADDRESS_IPV4) { | |
103 | return matches_ipv4_in_subnet(ifa, (struct sockaddr_in*)net, prefix_len); | |
104 | } | |
105 | break; | |
106 | case AF_INET6: | |
107 | if (ipv & CEPH_PICK_ADDRESS_IPV6) { | |
108 | return matches_ipv6_in_subnet(ifa, (struct sockaddr_in6*)net, prefix_len); | |
109 | } | |
110 | break; | |
111 | } | |
112 | return false; | |
113 | } | |
114 | ||
115 | bool matches_with_net(CephContext *cct, | |
116 | const ifaddrs& ifa, | |
117 | const std::string& s, | |
118 | unsigned ipv) | |
119 | { | |
120 | struct sockaddr_storage net; | |
121 | unsigned int prefix_len; | |
122 | if (!parse_network(s.c_str(), &net, &prefix_len)) { | |
123 | lderr(cct) << "unable to parse network: " << s << dendl; | |
124 | exit(1); | |
125 | } | |
126 | return matches_with_net(ifa, (sockaddr*)&net, prefix_len, ipv); | |
127 | } | |
128 | ||
129 | int grade_with_numa_node(const ifaddrs& ifa, int numa_node) | |
130 | { | |
131 | #if defined(WITH_SEASTAR) || defined(_WIN32) | |
132 | return 0; | |
133 | #else | |
134 | if (numa_node < 0) { | |
135 | return 0; | |
136 | } | |
137 | int if_node = -1; | |
138 | int r = get_iface_numa_node(ifa.ifa_name, &if_node); | |
139 | if (r < 0) { | |
140 | return 0; | |
141 | } | |
142 | return if_node == numa_node ? 1 : 0; | |
143 | #endif | |
144 | } | |
145 | } | |
146 | ||
3efd9988 FG |
147 | const struct sockaddr *find_ip_in_subnet_list( |
148 | CephContext *cct, | |
149 | const struct ifaddrs *ifa, | |
11fdf7f2 | 150 | unsigned ipv, |
3efd9988 | 151 | const std::string &networks, |
11fdf7f2 TL |
152 | const std::string &interfaces, |
153 | int numa_node) | |
7c673cae | 154 | { |
522d829b TL |
155 | const auto ifs = get_str_list(interfaces); |
156 | const auto nets = get_str_list(networks); | |
157 | if (!ifs.empty() && nets.empty()) { | |
3efd9988 FG |
158 | lderr(cct) << "interface names specified but not network names" << dendl; |
159 | exit(1); | |
3efd9988 | 160 | } |
7c673cae | 161 | |
522d829b TL |
162 | int best_score = 0; |
163 | const sockaddr* best_addr = nullptr; | |
164 | for (const auto* addr = ifa; addr != nullptr; addr = addr->ifa_next) { | |
165 | if (!ifs.empty() && | |
166 | std::none_of(std::begin(ifs), std::end(ifs), | |
167 | [&](const auto& if_name) { | |
168 | return matches_with_name(*addr, if_name); | |
169 | })) { | |
170 | continue; | |
3efd9988 | 171 | } |
522d829b TL |
172 | if (!nets.empty() && |
173 | std::none_of(std::begin(nets), std::end(nets), | |
174 | [&](const auto& net) { | |
175 | return matches_with_net(cct, *addr, net, ipv); | |
176 | })) { | |
177 | continue; | |
11fdf7f2 | 178 | } |
522d829b TL |
179 | int score = grade_addr(*addr); |
180 | if (score < 0) { | |
181 | continue; | |
3efd9988 | 182 | } |
522d829b TL |
183 | score += grade_with_numa_node(*addr, numa_node); |
184 | if (score > best_score) { | |
185 | best_score = score; | |
186 | best_addr = addr->ifa_addr; | |
7c673cae | 187 | } |
3efd9988 | 188 | } |
522d829b | 189 | return best_addr; |
7c673cae FG |
190 | } |
191 | ||
11fdf7f2 | 192 | #ifndef WITH_SEASTAR |
7c673cae FG |
193 | // observe this change |
194 | struct Observer : public md_config_obs_t { | |
195 | const char *keys[2]; | |
196 | explicit Observer(const char *c) { | |
197 | keys[0] = c; | |
198 | keys[1] = NULL; | |
199 | } | |
200 | ||
201 | const char** get_tracked_conf_keys() const override { | |
202 | return (const char **)keys; | |
203 | } | |
11fdf7f2 | 204 | void handle_conf_change(const ConfigProxy& conf, |
7c673cae FG |
205 | const std::set <std::string> &changed) override { |
206 | // do nothing. | |
207 | } | |
208 | }; | |
209 | ||
210 | static void fill_in_one_address(CephContext *cct, | |
211 | const struct ifaddrs *ifa, | |
522d829b TL |
212 | const string &networks, |
213 | const string &interfaces, | |
11fdf7f2 TL |
214 | const char *conf_var, |
215 | int numa_node = -1) | |
7c673cae | 216 | { |
11fdf7f2 TL |
217 | const struct sockaddr *found = find_ip_in_subnet_list( |
218 | cct, | |
219 | ifa, | |
220 | CEPH_PICK_ADDRESS_IPV4|CEPH_PICK_ADDRESS_IPV6, | |
221 | networks, | |
222 | interfaces, | |
223 | numa_node); | |
7c673cae | 224 | if (!found) { |
3efd9988 FG |
225 | lderr(cct) << "unable to find any IP address in networks '" << networks |
226 | << "' interfaces '" << interfaces << "'" << dendl; | |
7c673cae FG |
227 | exit(1); |
228 | } | |
229 | ||
230 | char buf[INET6_ADDRSTRLEN]; | |
231 | int err; | |
232 | ||
233 | err = getnameinfo(found, | |
234 | (found->sa_family == AF_INET) | |
235 | ? sizeof(struct sockaddr_in) | |
236 | : sizeof(struct sockaddr_in6), | |
237 | ||
238 | buf, sizeof(buf), | |
11fdf7f2 | 239 | nullptr, 0, |
7c673cae FG |
240 | NI_NUMERICHOST); |
241 | if (err != 0) { | |
242 | lderr(cct) << "unable to convert chosen address to string: " << gai_strerror(err) << dendl; | |
243 | exit(1); | |
244 | } | |
245 | ||
246 | Observer obs(conf_var); | |
247 | ||
11fdf7f2 | 248 | cct->_conf.add_observer(&obs); |
7c673cae | 249 | |
11fdf7f2 TL |
250 | cct->_conf.set_val_or_die(conf_var, buf); |
251 | cct->_conf.apply_changes(nullptr); | |
7c673cae | 252 | |
11fdf7f2 | 253 | cct->_conf.remove_observer(&obs); |
7c673cae FG |
254 | } |
255 | ||
256 | void pick_addresses(CephContext *cct, int needs) | |
257 | { | |
11fdf7f2 TL |
258 | auto public_addr = cct->_conf.get_val<entity_addr_t>("public_addr"); |
259 | auto public_network = cct->_conf.get_val<std::string>("public_network"); | |
260 | auto public_network_interface = | |
261 | cct->_conf.get_val<std::string>("public_network_interface"); | |
262 | auto cluster_addr = cct->_conf.get_val<entity_addr_t>("cluster_addr"); | |
263 | auto cluster_network = cct->_conf.get_val<std::string>("cluster_network"); | |
264 | auto cluster_network_interface = | |
265 | cct->_conf.get_val<std::string>("cluster_network_interface"); | |
266 | ||
522d829b TL |
267 | struct ifaddrs *ifa; |
268 | int r = getifaddrs(&ifa); | |
11fdf7f2 | 269 | if (r < 0) { |
7c673cae FG |
270 | string err = cpp_strerror(errno); |
271 | lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl; | |
272 | exit(1); | |
273 | } | |
522d829b | 274 | auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); |
11fdf7f2 TL |
275 | if ((needs & CEPH_PICK_ADDRESS_PUBLIC) && |
276 | public_addr.is_blank_ip() && !public_network.empty()) { | |
277 | fill_in_one_address(cct, ifa, public_network, public_network_interface, | |
522d829b | 278 | "public_addr"); |
7c673cae FG |
279 | } |
280 | ||
11fdf7f2 TL |
281 | if ((needs & CEPH_PICK_ADDRESS_CLUSTER) && cluster_addr.is_blank_ip()) { |
282 | if (!cluster_network.empty()) { | |
283 | fill_in_one_address(cct, ifa, cluster_network, cluster_network_interface, | |
522d829b | 284 | "cluster_addr"); |
7c673cae | 285 | } else { |
11fdf7f2 | 286 | if (!public_network.empty()) { |
7c673cae FG |
287 | lderr(cct) << "Public network was set, but cluster network was not set " << dendl; |
288 | lderr(cct) << " Using public network also for cluster network" << dendl; | |
11fdf7f2 | 289 | fill_in_one_address(cct, ifa, public_network, public_network_interface, |
522d829b | 290 | "cluster_addr"); |
7c673cae FG |
291 | } |
292 | } | |
293 | } | |
7c673cae | 294 | } |
11fdf7f2 TL |
295 | #endif // !WITH_SEASTAR |
296 | ||
297 | static int fill_in_one_address( | |
298 | CephContext *cct, | |
299 | const struct ifaddrs *ifa, | |
300 | unsigned ipv, | |
522d829b TL |
301 | const string &networks, |
302 | const string &interfaces, | |
11fdf7f2 TL |
303 | entity_addrvec_t *addrs, |
304 | int numa_node = -1) | |
305 | { | |
522d829b TL |
306 | const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, ipv, |
307 | networks, | |
308 | interfaces, | |
309 | numa_node); | |
11fdf7f2 TL |
310 | if (!found) { |
311 | std::string ip_type = ""; | |
312 | if ((ipv & CEPH_PICK_ADDRESS_IPV4) && (ipv & CEPH_PICK_ADDRESS_IPV6)) { | |
313 | ip_type = "IPv4 or IPv6"; | |
314 | } else if (ipv & CEPH_PICK_ADDRESS_IPV4) { | |
315 | ip_type = "IPv4"; | |
316 | } else { | |
317 | ip_type = "IPv6"; | |
318 | } | |
319 | lderr(cct) << "unable to find any " << ip_type << " address in networks '" | |
320 | << networks << "' interfaces '" << interfaces << "'" << dendl; | |
321 | return -1; | |
322 | } | |
323 | ||
324 | char buf[INET6_ADDRSTRLEN]; | |
325 | int err; | |
7c673cae | 326 | |
11fdf7f2 TL |
327 | err = getnameinfo(found, |
328 | (found->sa_family == AF_INET) | |
329 | ? sizeof(struct sockaddr_in) | |
330 | : sizeof(struct sockaddr_in6), | |
331 | ||
332 | buf, sizeof(buf), | |
333 | nullptr, 0, | |
334 | NI_NUMERICHOST); | |
335 | if (err != 0) { | |
336 | lderr(cct) << "unable to convert chosen address to string: " << gai_strerror(err) << dendl; | |
337 | return -1; | |
338 | } | |
339 | ||
340 | entity_addr_t addr; | |
341 | const char *end = 0; | |
342 | bool r = addr.parse(buf, &end); | |
343 | if (!r) { | |
344 | return -1; | |
345 | } | |
346 | addrs->v.push_back(addr); | |
347 | return 0; | |
348 | } | |
349 | ||
350 | int pick_addresses( | |
351 | CephContext *cct, | |
352 | unsigned flags, | |
353 | struct ifaddrs *ifa, | |
354 | entity_addrvec_t *addrs, | |
355 | int preferred_numa_node) | |
356 | { | |
357 | addrs->v.clear(); | |
358 | ||
359 | unsigned addrt = (flags & (CEPH_PICK_ADDRESS_PUBLIC | | |
360 | CEPH_PICK_ADDRESS_CLUSTER)); | |
361 | if (addrt == 0 || | |
362 | addrt == (CEPH_PICK_ADDRESS_PUBLIC | | |
363 | CEPH_PICK_ADDRESS_CLUSTER)) { | |
364 | return -EINVAL; | |
365 | } | |
366 | unsigned msgrv = flags & (CEPH_PICK_ADDRESS_MSGR1 | | |
367 | CEPH_PICK_ADDRESS_MSGR2); | |
368 | if (msgrv == 0) { | |
369 | if (cct->_conf.get_val<bool>("ms_bind_msgr1")) { | |
370 | msgrv |= CEPH_PICK_ADDRESS_MSGR1; | |
371 | } | |
372 | if (cct->_conf.get_val<bool>("ms_bind_msgr2")) { | |
373 | msgrv |= CEPH_PICK_ADDRESS_MSGR2; | |
374 | } | |
375 | if (msgrv == 0) { | |
376 | return -EINVAL; | |
377 | } | |
378 | } | |
379 | unsigned ipv = flags & (CEPH_PICK_ADDRESS_IPV4 | | |
380 | CEPH_PICK_ADDRESS_IPV6); | |
381 | if (ipv == 0) { | |
382 | if (cct->_conf.get_val<bool>("ms_bind_ipv4")) { | |
383 | ipv |= CEPH_PICK_ADDRESS_IPV4; | |
384 | } | |
385 | if (cct->_conf.get_val<bool>("ms_bind_ipv6")) { | |
386 | ipv |= CEPH_PICK_ADDRESS_IPV6; | |
387 | } | |
388 | if (ipv == 0) { | |
389 | return -EINVAL; | |
390 | } | |
391 | if (cct->_conf.get_val<bool>("ms_bind_prefer_ipv4")) { | |
392 | flags |= CEPH_PICK_ADDRESS_PREFER_IPV4; | |
393 | } else { | |
394 | flags &= ~CEPH_PICK_ADDRESS_PREFER_IPV4; | |
395 | } | |
396 | } | |
397 | ||
398 | entity_addr_t addr; | |
399 | string networks; | |
400 | string interfaces; | |
401 | if (addrt & CEPH_PICK_ADDRESS_PUBLIC) { | |
402 | addr = cct->_conf.get_val<entity_addr_t>("public_addr"); | |
403 | networks = cct->_conf.get_val<std::string>("public_network"); | |
404 | interfaces = | |
405 | cct->_conf.get_val<std::string>("public_network_interface"); | |
406 | } else { | |
407 | addr = cct->_conf.get_val<entity_addr_t>("cluster_addr"); | |
408 | networks = cct->_conf.get_val<std::string>("cluster_network"); | |
409 | interfaces = | |
410 | cct->_conf.get_val<std::string>("cluster_network_interface"); | |
411 | if (networks.empty()) { | |
412 | lderr(cct) << "Falling back to public interface" << dendl; | |
413 | // fall back to public_ network and interface if cluster is not set | |
414 | networks = cct->_conf.get_val<std::string>("public_network"); | |
415 | interfaces = | |
416 | cct->_conf.get_val<std::string>("public_network_interface"); | |
417 | } | |
418 | } | |
419 | if (addr.is_blank_ip() && | |
420 | !networks.empty()) { | |
421 | int ipv4_r = !(ipv & CEPH_PICK_ADDRESS_IPV4) ? 0 : -1; | |
422 | int ipv6_r = !(ipv & CEPH_PICK_ADDRESS_IPV6) ? 0 : -1; | |
522d829b TL |
423 | // note: pass in ipv to filter the matching addresses |
424 | if ((ipv & CEPH_PICK_ADDRESS_IPV4) && | |
425 | (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { | |
426 | ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, | |
427 | networks, interfaces, | |
428 | addrs, | |
429 | preferred_numa_node); | |
430 | } | |
431 | if (ipv & CEPH_PICK_ADDRESS_IPV6) { | |
432 | ipv6_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV6, | |
433 | networks, interfaces, | |
434 | addrs, | |
435 | preferred_numa_node); | |
436 | } | |
437 | if ((ipv & CEPH_PICK_ADDRESS_IPV4) && | |
438 | !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { | |
439 | ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, | |
440 | networks, interfaces, | |
441 | addrs, | |
442 | preferred_numa_node); | |
443 | } | |
444 | if (ipv4_r < 0 || ipv6_r < 0) { | |
445 | return -1; | |
11fdf7f2 TL |
446 | } |
447 | } | |
448 | ||
449 | // note: we may have a blank addr here | |
450 | ||
451 | // ipv4 and/or ipv6? | |
452 | if (addrs->v.empty()) { | |
11fdf7f2 TL |
453 | addr.set_type(entity_addr_t::TYPE_MSGR2); |
454 | if ((ipv & CEPH_PICK_ADDRESS_IPV4) && | |
455 | (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { | |
456 | addr.set_family(AF_INET); | |
457 | addrs->v.push_back(addr); | |
458 | } | |
459 | if (ipv & CEPH_PICK_ADDRESS_IPV6) { | |
460 | addr.set_family(AF_INET6); | |
461 | addrs->v.push_back(addr); | |
462 | } | |
463 | if ((ipv & CEPH_PICK_ADDRESS_IPV4) && | |
464 | !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { | |
465 | addr.set_family(AF_INET); | |
466 | addrs->v.push_back(addr); | |
467 | } | |
468 | } | |
469 | ||
470 | // msgr2 or legacy or both? | |
471 | if (msgrv == (CEPH_PICK_ADDRESS_MSGR1 | CEPH_PICK_ADDRESS_MSGR2)) { | |
472 | vector<entity_addr_t> v; | |
473 | v.swap(addrs->v); | |
474 | for (auto a : v) { | |
475 | a.set_type(entity_addr_t::TYPE_MSGR2); | |
476 | if (flags & CEPH_PICK_ADDRESS_DEFAULT_MON_PORTS) { | |
477 | a.set_port(CEPH_MON_PORT_IANA); | |
478 | } | |
479 | addrs->v.push_back(a); | |
480 | a.set_type(entity_addr_t::TYPE_LEGACY); | |
481 | if (flags & CEPH_PICK_ADDRESS_DEFAULT_MON_PORTS) { | |
482 | a.set_port(CEPH_MON_PORT_LEGACY); | |
483 | } | |
484 | addrs->v.push_back(a); | |
485 | } | |
486 | } else if (msgrv == CEPH_PICK_ADDRESS_MSGR1) { | |
487 | for (auto& a : addrs->v) { | |
488 | a.set_type(entity_addr_t::TYPE_LEGACY); | |
489 | } | |
490 | } else { | |
491 | for (auto& a : addrs->v) { | |
492 | a.set_type(entity_addr_t::TYPE_MSGR2); | |
493 | } | |
494 | } | |
495 | ||
496 | return 0; | |
497 | } | |
498 | ||
499 | int pick_addresses( | |
500 | CephContext *cct, | |
501 | unsigned flags, | |
502 | entity_addrvec_t *addrs, | |
503 | int preferred_numa_node) | |
504 | { | |
505 | struct ifaddrs *ifa; | |
506 | int r = getifaddrs(&ifa); | |
507 | if (r < 0) { | |
508 | r = -errno; | |
509 | string err = cpp_strerror(r); | |
510 | lderr(cct) << "unable to fetch interfaces and addresses: " | |
511 | << cpp_strerror(r) << dendl; | |
512 | return r; | |
513 | } | |
514 | r = pick_addresses(cct, flags, ifa, addrs, preferred_numa_node); | |
515 | freeifaddrs(ifa); | |
516 | return r; | |
517 | } | |
b5b8bbf5 FG |
518 | |
519 | std::string pick_iface(CephContext *cct, const struct sockaddr_storage &network) | |
520 | { | |
521 | struct ifaddrs *ifa; | |
522 | int r = getifaddrs(&ifa); | |
523 | if (r < 0) { | |
524 | string err = cpp_strerror(errno); | |
525 | lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl; | |
526 | return {}; | |
527 | } | |
522d829b | 528 | auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); |
f67539c2 | 529 | const unsigned int prefix_len = std::max(sizeof(in_addr::s_addr), sizeof(in6_addr::s6_addr)) * CHAR_BIT; |
522d829b TL |
530 | for (auto addr = ifa; addr != nullptr; addr = addr->ifa_next) { |
531 | if (matches_with_net(*ifa, (const struct sockaddr *) &network, prefix_len, | |
532 | CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6)) { | |
533 | return addr->ifa_name; | |
534 | } | |
b5b8bbf5 | 535 | } |
522d829b | 536 | return {}; |
b5b8bbf5 FG |
537 | } |
538 | ||
539 | ||
f67539c2 | 540 | bool have_local_addr(CephContext *cct, const std::list<entity_addr_t>& ls, entity_addr_t *match) |
7c673cae FG |
541 | { |
542 | struct ifaddrs *ifa; | |
543 | int r = getifaddrs(&ifa); | |
544 | if (r < 0) { | |
545 | lderr(cct) << "unable to fetch interfaces and addresses: " << cpp_strerror(errno) << dendl; | |
546 | exit(1); | |
547 | } | |
522d829b | 548 | auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); |
7c673cae | 549 | |
11fdf7f2 | 550 | for (struct ifaddrs *addrs = ifa; addrs != nullptr; addrs = addrs->ifa_next) { |
7c673cae FG |
551 | if (addrs->ifa_addr) { |
552 | entity_addr_t a; | |
553 | a.set_sockaddr(addrs->ifa_addr); | |
11fdf7f2 TL |
554 | for (auto& p : ls) { |
555 | if (a.is_same_host(p)) { | |
556 | *match = p; | |
522d829b | 557 | return true; |
7c673cae FG |
558 | } |
559 | } | |
560 | } | |
561 | } | |
522d829b | 562 | return false; |
7c673cae | 563 | } |
11fdf7f2 TL |
564 | |
565 | int get_iface_numa_node( | |
566 | const std::string& iface, | |
567 | int *node) | |
568 | { | |
9f95a23c TL |
569 | enum class iface_t { |
570 | PHY_PORT, | |
571 | BOND_PORT | |
572 | } ifatype = iface_t::PHY_PORT; | |
f67539c2 | 573 | std::string_view ifa{iface}; |
9f95a23c TL |
574 | if (auto pos = ifa.find(":"); pos != ifa.npos) { |
575 | ifa.remove_suffix(ifa.size() - pos); | |
92f5a8d4 | 576 | } |
9f95a23c | 577 | string fn = fmt::format("/sys/class/net/{}/device/numa_node", ifa); |
92f5a8d4 TL |
578 | int fd = ::open(fn.c_str(), O_RDONLY); |
579 | if (fd < 0) { | |
9f95a23c | 580 | fn = fmt::format("/sys/class/net/{}/bonding/slaves", ifa); |
92f5a8d4 TL |
581 | fd = ::open(fn.c_str(), O_RDONLY); |
582 | if (fd < 0) { | |
583 | return -errno; | |
584 | } | |
9f95a23c | 585 | ifatype = iface_t::BOND_PORT; |
92f5a8d4 | 586 | } |
11fdf7f2 TL |
587 | |
588 | int r = 0; | |
589 | char buf[1024]; | |
590 | char *endptr = 0; | |
11fdf7f2 TL |
591 | r = safe_read(fd, &buf, sizeof(buf)); |
592 | if (r < 0) { | |
593 | goto out; | |
594 | } | |
595 | buf[r] = 0; | |
596 | while (r > 0 && ::isspace(buf[--r])) { | |
597 | buf[r] = 0; | |
598 | } | |
92f5a8d4 TL |
599 | |
600 | switch (ifatype) { | |
9f95a23c | 601 | case iface_t::PHY_PORT: |
92f5a8d4 TL |
602 | *node = strtoll(buf, &endptr, 10); |
603 | if (endptr != buf + strlen(buf)) { | |
604 | r = -EINVAL; | |
605 | goto out; | |
606 | } | |
607 | r = 0; | |
608 | break; | |
9f95a23c TL |
609 | case iface_t::BOND_PORT: |
610 | int bond_node = -1; | |
92f5a8d4 | 611 | std::vector<std::string> sv; |
9f95a23c TL |
612 | std::string ifacestr = buf; |
613 | get_str_vec(ifacestr, " ", sv); | |
92f5a8d4 TL |
614 | for (auto& iter : sv) { |
615 | int bn = -1; | |
616 | r = get_iface_numa_node(iter, &bn); | |
617 | if (r >= 0) { | |
618 | if (bond_node == -1 || bn == bond_node) { | |
619 | bond_node = bn; | |
620 | } else { | |
621 | *node = -2; | |
622 | goto out; | |
623 | } | |
624 | } else { | |
625 | goto out; | |
626 | } | |
627 | } | |
628 | *node = bond_node; | |
629 | break; | |
11fdf7f2 | 630 | } |
92f5a8d4 TL |
631 | |
632 | out: | |
11fdf7f2 TL |
633 | ::close(fd); |
634 | return r; | |
635 | } | |
92f5a8d4 | 636 |