freeifaddrs(ifa);
}
+static int fill_in_one_address(
+ CephContext *cct,
+ const struct ifaddrs *ifa,
+ unsigned ipv,
+ const string networks,
+ const string interfaces,
+ entity_addrvec_t *addrs)
+{
+ const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, ipv, networks,
+ interfaces);
+ if (!found) {
+ return -1;
+ }
+
+ char buf[INET6_ADDRSTRLEN];
+ int err;
+
+ err = getnameinfo(found,
+ (found->sa_family == AF_INET)
+ ? sizeof(struct sockaddr_in)
+ : sizeof(struct sockaddr_in6),
+
+ buf, sizeof(buf),
+ nullptr, 0,
+ NI_NUMERICHOST);
+ if (err != 0) {
+ return -1;
+ }
+
+ entity_addr_t addr;
+ const char *end = 0;
+ bool r = addr.parse(buf, &end);
+ if (!r) {
+ return -1;
+ }
+ addrs->v.push_back(addr);
+ return 0;
+}
+
+int pick_addresses(
+ CephContext *cct,
+ unsigned flags,
+ struct ifaddrs *ifa,
+ entity_addrvec_t *addrs)
+{
+ addrs->v.clear();
+
+ unsigned addrt = (flags & (CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_CLUSTER));
+ if (addrt == 0 ||
+ addrt == (CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_CLUSTER)) {
+ return -EINVAL;
+ }
+ unsigned msgrv = flags & (CEPH_PICK_ADDRESS_MSGR1 |
+ CEPH_PICK_ADDRESS_MSGR2);
+ if (msgrv == 0) {
+ return -EINVAL;
+ }
+ unsigned ipv = flags & (CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_IPV6);
+ if (ipv == 0) {
+ return -EINVAL;
+ }
+
+ entity_addr_t addr;
+ string networks;
+ string interfaces;
+ if (addrt & CEPH_PICK_ADDRESS_PUBLIC) {
+ addr = cct->_conf->get_val<entity_addr_t>("public_addr");
+ networks = cct->_conf->get_val<std::string>("public_network");
+ interfaces =
+ cct->_conf->get_val<std::string>("public_network_interface");
+ } else {
+ addr = cct->_conf->get_val<entity_addr_t>("cluster_addr");
+ networks = cct->_conf->get_val<std::string>("cluster_network");
+ interfaces =
+ cct->_conf->get_val<std::string>("cluster_network_interface");
+ if (networks.empty()) {
+ // fall back to public_ network and interface if cluster is not set
+ networks = cct->_conf->get_val<std::string>("public_network");
+ interfaces =
+ cct->_conf->get_val<std::string>("public_network_interface");
+ }
+ }
+ if (addr.is_blank_ip() &&
+ !networks.empty()) {
+ // note: pass in ipv to filter the matching addresses
+ if ((ipv & CEPH_PICK_ADDRESS_IPV4) &&
+ (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) {
+ fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, networks, interfaces,
+ addrs);
+ }
+ if (ipv & CEPH_PICK_ADDRESS_IPV6) {
+ fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV6, networks, interfaces,
+ addrs);
+ }
+ if ((ipv & CEPH_PICK_ADDRESS_IPV4) &&
+ !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) {
+ fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, networks, interfaces,
+ addrs);
+ }
+ }
+
+ // note: we may have a blank addr here
+
+ // ipv4 and/or ipv6?
+ if (addrs->v.empty()) {
+ entity_addr_t addr;
+ addr.set_type(entity_addr_t::TYPE_MSGR2);
+ if ((ipv & CEPH_PICK_ADDRESS_IPV4) &&
+ (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) {
+ addr.set_family(AF_INET);
+ addrs->v.push_back(addr);
+ }
+ if (ipv & CEPH_PICK_ADDRESS_IPV6) {
+ addr.set_family(AF_INET6);
+ addrs->v.push_back(addr);
+ }
+ if ((ipv & CEPH_PICK_ADDRESS_IPV4) &&
+ !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) {
+ addr.set_family(AF_INET);
+ addrs->v.push_back(addr);
+ }
+ }
+
+ // msgr2 or legacy or both?
+ if (msgrv == (CEPH_PICK_ADDRESS_MSGR1 | CEPH_PICK_ADDRESS_MSGR2)) {
+ vector<entity_addr_t> v;
+ v.swap(addrs->v);
+ for (auto a : v) {
+ a.set_type(entity_addr_t::TYPE_MSGR2);
+ if (flags & CEPH_PICK_ADDRESS_DEFAULT_MON_PORTS) {
+ a.set_port(CEPH_MON_PORT_IANA);
+ }
+ addrs->v.push_back(a);
+ a.set_type(entity_addr_t::TYPE_LEGACY);
+ if (flags & CEPH_PICK_ADDRESS_DEFAULT_MON_PORTS) {
+ a.set_port(CEPH_MON_PORT_LEGACY);
+ }
+ addrs->v.push_back(a);
+ }
+ } else if (msgrv == CEPH_PICK_ADDRESS_MSGR1) {
+ for (auto& a : addrs->v) {
+ a.set_type(entity_addr_t::TYPE_LEGACY);
+ }
+ } else {
+ for (auto& a : addrs->v) {
+ a.set_type(entity_addr_t::TYPE_MSGR2);
+ }
+ }
+
+ return 0;
+}
+
+int pick_addresses(
+ CephContext *cct,
+ unsigned flags,
+ entity_addrvec_t *addrs)
+{
+ struct ifaddrs *ifa;
+ int r = getifaddrs(&ifa);
+ if (r < 0) {
+ r = -errno;
+ string err = cpp_strerror(r);
+ lderr(cct) << "unable to fetch interfaces and addresses: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+ r = pick_addresses(cct, flags, ifa, addrs);
+ freeifaddrs(ifa);
+ return r;
+}
std::string pick_iface(CephContext *cct, const struct sockaddr_storage &network)
{
}
const unsigned int prefix_len = max(sizeof(in_addr::s_addr), sizeof(in6_addr::s6_addr)) * CHAR_BIT;
- const struct ifaddrs *found = find_ip_in_subnet(ifa,
- (const struct sockaddr *) &network, prefix_len);
+ const struct ifaddrs *found = find_ip_in_subnet(
+ ifa,
+ (const struct sockaddr *) &network, prefix_len);
std::string result;
if (found) {
#include "common/pick_address.h"
#include "global/global_context.h"
#include "gtest/gtest.h"
+#include "include/stringify.h"
+#include "common/ceph_context.h"
#if defined(__FreeBSD__)
#include <sys/types.h>
"eth1");
ASSERT_EQ((struct sockaddr*)&a_three, result);
}
+
+TEST(pick_address, filtering)
+{
+ struct ifaddrs one, two, three;
+ struct sockaddr_in a_one;
+ struct sockaddr_in a_two;
+ struct sockaddr_in6 a_three;
+
+ one.ifa_next = &two;
+ one.ifa_addr = (struct sockaddr*)&a_one;
+ one.ifa_name = eth0;
+
+ two.ifa_next = &three;
+ two.ifa_addr = (struct sockaddr*)&a_two;
+ two.ifa_name = eth1;
+
+ three.ifa_next = NULL;
+ three.ifa_addr = (struct sockaddr*)&a_three;
+ three.ifa_name = eth1;
+
+ ipv4(&a_one, "10.1.1.2");
+ ipv4(&a_two, "10.2.1.123");
+ ipv6(&a_three, "2001:1234:5678:90ab::cdef");
+
+ CephContext *cct = new CephContext(CEPH_ENTITY_TYPE_MON);
+ cct->_conf->_clear_safe_to_start_threads(); // so we can set configs
+
+ cct->_conf->set_val("public_addr", "");
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("public_network_interface", "");
+ cct->_conf->set_val("cluster_addr", "");
+ cct->_conf->set_val("cluster_network", "");
+ cct->_conf->set_val("cluster_network_interface", "");
+
+ entity_addrvec_t av;
+ {
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("0.0.0.0:0/0"), stringify(av.v[0]));
+ }
+ {
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV6 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("[::]:0/0"), stringify(av.v[0]));
+ }
+ {
+ cct->_conf->set_val("public_network", "10.2.0.0/16");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("10.2.1.123:0/0"), stringify(av.v[0]));
+ cct->_conf->set_val("public_network", "");
+ }
+ {
+ cct->_conf->set_val("public_network", "10.0.0.0/8");
+ cct->_conf->set_val("public_network_interface", "eth1");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("10.2.1.123:0/0"), stringify(av.v[0]));
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("public_network_interface", "");
+ }
+ {
+ cct->_conf->set_val("public_network", "10.2.0.0/16");
+ cct->_conf->set_val("cluster_network", "10.1.0.0/16");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("10.2.1.123:0/0"), stringify(av.v[0]));
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("cluster_network", "");
+ }
+ {
+ cct->_conf->set_val("public_network", "10.2.0.0/16");
+ cct->_conf->set_val("cluster_network", "10.1.0.0/16");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_CLUSTER |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("10.1.1.2:0/0"), stringify(av.v[0]));
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("cluster_network", "");
+ }
+
+ {
+ cct->_conf->set_val("public_network", "2001::/16");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV6 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(1, av.v.size());
+ ASSERT_EQ(string("[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0]));
+ cct->_conf->set_val("public_network", "");
+ }
+ {
+ cct->_conf->set_val("public_network", "2001::/16 10.0.0.0/8");
+ cct->_conf->set_val("public_network_interface", "eth1");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_IPV6 |
+ CEPH_PICK_ADDRESS_MSGR1,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(2, av.v.size());
+ ASSERT_EQ(string("[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0]));
+ ASSERT_EQ(string("10.2.1.123:0/0"), stringify(av.v[1]));
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("public_network_interface", "");
+ }
+ {
+ cct->_conf->set_val("public_network", "2001::/16 10.0.0.0/8");
+ cct->_conf->set_val("public_network_interface", "eth1");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_IPV6 |
+ CEPH_PICK_ADDRESS_MSGR1 |
+ CEPH_PICK_ADDRESS_PREFER_IPV4,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(2, av.v.size());
+ ASSERT_EQ(string("10.2.1.123:0/0"), stringify(av.v[0]));
+ ASSERT_EQ(string("[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[1]));
+ cct->_conf->set_val("public_network", "");
+ cct->_conf->set_val("public_network_interface", "");
+ }
+
+ {
+ cct->_conf->set_val("public_network", "2001::/16");
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV6 |
+ CEPH_PICK_ADDRESS_MSGR1 |
+ CEPH_PICK_ADDRESS_MSGR2,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(2, av.v.size());
+ ASSERT_EQ(string("msgr2:[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[0]));
+ ASSERT_EQ(string("[2001:1234:5678:90ab::cdef]:0/0"), stringify(av.v[1]));
+ cct->_conf->set_val("public_network", "");
+ }
+
+ {
+ int r = pick_addresses(cct,
+ CEPH_PICK_ADDRESS_PUBLIC |
+ CEPH_PICK_ADDRESS_IPV4 |
+ CEPH_PICK_ADDRESS_MSGR1 |
+ CEPH_PICK_ADDRESS_MSGR2,
+ &one, &av);
+ cout << av << std::endl;
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(2, av.v.size());
+ ASSERT_EQ(string("msgr2:0.0.0.0:0/0"), stringify(av.v[0]));
+ ASSERT_EQ(string("0.0.0.0:0/0"), stringify(av.v[1]));
+ }
+}