Option("public_network", Option::TYPE_STR, Option::LEVEL_ADVANCED)
.add_service({"mon", "mds", "osd", "mgr"})
.add_tag("network")
- .set_description(""),
+ .set_description("Network(s) from which to choose a public address to bind to"),
+
+ Option("public_network_interface", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+ .add_service({"mon", "mds", "osd", "mgr"})
+ .add_tag("network")
+ .set_description("Interface name(s) from which to choose an address from a public_network to bind to; public_network must also be specified.")
+ .add_see_also("public_network"),
Option("cluster_network", Option::TYPE_STR, Option::LEVEL_ADVANCED)
.add_service("osd")
.add_tag("network")
- .set_description(""),
+ .set_description("Network(s) from which to choose a cluster address to bind to"),
+
+ Option("cluster_network_interface", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+ .add_service({"mon", "mds", "osd", "mgr"})
+ .add_tag("network")
+ .set_description("Interface name(s) from which to choose an address from a cluster_network to bind to; cluster_network must also be specified.")
+ .add_see_also("cluster_network"),
Option("monmap", Option::TYPE_STR, Option::LEVEL_ADVANCED)
.set_description("path to MonMap file")
#define dout_subsys ceph_subsys_
-static const struct sockaddr *find_ip_in_subnet_list(CephContext *cct,
- const struct ifaddrs *ifa,
- const std::string &networks)
+const struct sockaddr *find_ip_in_subnet_list(
+ CephContext *cct,
+ const struct ifaddrs *ifa,
+ const std::string &networks,
+ const std::string &interfaces)
{
std::list<string> nets;
get_str_list(networks, nets);
+ std::list<string> ifs;
+ get_str_list(interfaces, ifs);
+
+ // filter interfaces by name
+ const struct ifaddrs *filtered = 0;
+ if (ifs.empty()) {
+ filtered = ifa;
+ } else {
+ if (nets.empty()) {
+ lderr(cct) << "interface names specified but not network names" << dendl;
+ exit(1);
+ }
+ const struct ifaddrs *t = ifa;
+ struct ifaddrs *head = 0;
+ while (t != NULL) {
+ bool match = false;
+ for (auto& i : ifs) {
+ if (strcmp(i.c_str(), t->ifa_name) == 0) {
+ match = true;
+ break;
+ }
+ }
+ if (match) {
+ struct ifaddrs *n = new ifaddrs;
+ memcpy(n, t, sizeof(*t));
+ n->ifa_next = head;
+ head = n;
+ }
+ t = t->ifa_next;
+ }
+ if (head == NULL) {
+ lderr(cct) << "no interfaces matching " << ifs << dendl;
+ exit(1);
+ }
+ filtered = head;
+ }
- for(std::list<string>::iterator s = nets.begin(); s != nets.end(); ++s) {
- struct sockaddr_storage net;
- unsigned int prefix_len;
+ struct sockaddr *r = NULL;
+ for (std::list<string>::iterator s = nets.begin(); s != nets.end(); ++s) {
+ struct sockaddr_storage net;
+ unsigned int prefix_len;
- if (!parse_network(s->c_str(), &net, &prefix_len)) {
- lderr(cct) << "unable to parse network: " << *s << dendl;
- exit(1);
- }
+ if (!parse_network(s->c_str(), &net, &prefix_len)) {
+ lderr(cct) << "unable to parse network: " << *s << dendl;
+ exit(1);
+ }
+
+ const struct ifaddrs *found = find_ip_in_subnet(
+ filtered,
+ (struct sockaddr *) &net, prefix_len);
+ if (found) {
+ r = found->ifa_addr;
+ break;
+ }
+ }
- const struct ifaddrs *found = find_ip_in_subnet(ifa,
- (struct sockaddr *) &net, prefix_len);
- if (found)
- return found->ifa_addr;
+ if (filtered != ifa) {
+ while (filtered) {
+ struct ifaddrs *t = filtered->ifa_next;
+ delete filtered;
+ filtered = t;
}
+ }
- return NULL;
+ return r;
}
// observe this change
static void fill_in_one_address(CephContext *cct,
const struct ifaddrs *ifa,
const string networks,
+ const string interfaces,
const char *conf_var)
{
- const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, networks);
+ const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, networks,
+ interfaces);
if (!found) {
- lderr(cct) << "unable to find any IP address in networks: " << networks << dendl;
+ lderr(cct) << "unable to find any IP address in networks '" << networks
+ << "' interfaces '" << interfaces << "'" << dendl;
exit(1);
}
exit(1);
}
-
if ((needs & CEPH_PICK_ADDRESS_PUBLIC)
&& cct->_conf->public_addr.is_blank_ip()
&& !cct->_conf->public_network.empty()) {
- fill_in_one_address(cct, ifa, cct->_conf->public_network, "public_addr");
+ fill_in_one_address(cct, ifa, cct->_conf->public_network,
+ cct->_conf->get_val<string>("public_network_interface"),
+ "public_addr");
}
if ((needs & CEPH_PICK_ADDRESS_CLUSTER)
&& cct->_conf->cluster_addr.is_blank_ip()) {
if (!cct->_conf->cluster_network.empty()) {
- fill_in_one_address(cct, ifa, cct->_conf->cluster_network, "cluster_addr");
+ fill_in_one_address(
+ cct, ifa, cct->_conf->cluster_network,
+ cct->_conf->get_val<string>("cluster_network_interface"),
+ "cluster_addr");
} else {
if (!cct->_conf->public_network.empty()) {
lderr(cct) << "Public network was set, but cluster network was not set " << dendl;
lderr(cct) << " Using public network also for cluster network" << dendl;
- fill_in_one_address(cct, ifa, cct->_conf->public_network, "cluster_addr");
+ fill_in_one_address(
+ cct, ifa, cct->_conf->public_network,
+ cct->_conf->get_val<string>("public_network_interface"),
+ "cluster_addr");
}
}
}
#include "include/ipaddr.h"
+#include "common/pick_address.h"
+#include "global/global_context.h"
#include "gtest/gtest.h"
#if defined(__FreeBSD__)
ipv6(&want, "2001:1234:5678:90ab::dead:beef");
ASSERT_EQ(0, memcmp(want.sin6_addr.s6_addr, network.sin6_addr.s6_addr, sizeof(network.sin6_addr.s6_addr)));
}
+
+TEST(pick_address, find_ip_in_subnet_list)
+{
+ struct ifaddrs one, two;
+ struct sockaddr_in a_one;
+ struct sockaddr_in a_two;
+ const struct sockaddr *result;
+
+ one.ifa_next = &two;
+ one.ifa_addr = (struct sockaddr*)&a_one;
+ one.ifa_name = eth0;
+
+ two.ifa_next = NULL;
+ two.ifa_addr = (struct sockaddr*)&a_two;
+ two.ifa_name = eth1;
+
+ ipv4(&a_one, "10.1.1.2");
+ ipv4(&a_two, "10.2.1.123");
+
+ // match by network
+ result = find_ip_in_subnet_list(
+ g_ceph_context,
+ &one,
+ "10.1.0.0/16",
+ "eth0");
+ ASSERT_EQ((struct sockaddr*)&a_one, result);
+
+ result = find_ip_in_subnet_list(
+ g_ceph_context,
+ &one,
+ "10.2.0.0/16",
+ "eth1");
+ ASSERT_EQ((struct sockaddr*)&a_two, result);
+
+ // match by eth name
+ result = find_ip_in_subnet_list(
+ g_ceph_context,
+ &one,
+ "10.0.0.0/8",
+ "eth0");
+ ASSERT_EQ((struct sockaddr*)&a_one, result);
+
+ result = find_ip_in_subnet_list(
+ g_ceph_context,
+ &one,
+ "10.0.0.0/8",
+ "eth1");
+ ASSERT_EQ((struct sockaddr*)&a_two, result);
+}