summaryrefslogtreecommitdiff
path: root/src/common/pick_address.cc
blob: 38a5751c042fbf25bccbd7c77402ad41d5114d23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2012 Inktank
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "common/pick_address.h"

#include <netdb.h>
#include <errno.h>

#include "include/ipaddr.h"
#include "include/str_list.h"
#include "common/debug.h"
#include "common/errno.h"

#define dout_subsys ceph_subsys_

static const struct sockaddr *find_ip_in_subnet_list(CephContext *cct,
						     const struct ifaddrs *ifa,
						     const std::string networks)
{
  std::list<string> nets;
  get_str_list(networks, nets);

  for(std::list<string>::iterator s = nets.begin(); s != nets.end(); s++) {
      struct sockaddr net;
      unsigned int prefix_len;

      if (!parse_network(s->c_str(), &net, &prefix_len)) {
	lderr(cct) << "unable to parse network: " << *s << dendl;
	exit(1);
      }

      const struct sockaddr *found = find_ip_in_subnet(ifa, &net, prefix_len);
      if (found)
	return found;
    }

  return NULL;
}

static void fill_in_one_address(CephContext *cct,
				const struct ifaddrs *ifa,
				const string networks,
				const char *conf_var)
{
  const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, networks);
  if (!found) {
    lderr(cct) << "unable to find any IP address in networks: " << networks << dendl;
    exit(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),
		    NULL, 0,
		    NI_NUMERICHOST);
  if (err != 0) {
    lderr(cct) << "unable to convert chosen address to string: " << gai_strerror(err) << dendl;
    exit(1);
  }

  cct->_conf->set_val_or_die(conf_var, buf);
  cct->_conf->apply_changes(NULL);
}

void pick_addresses(CephContext *cct)
{
  struct ifaddrs *ifa;
  int r = getifaddrs(&ifa);
  if (r<0) {
    string err = cpp_strerror(errno);
    lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl;
    exit(1);
  }

  if (cct->_conf->public_addr.is_blank_ip() && !cct->_conf->public_network.empty()) {
    fill_in_one_address(cct, ifa, cct->_conf->public_network, "public_addr");
  }

  if (cct->_conf->cluster_addr.is_blank_ip() && !cct->_conf->cluster_network.empty()) {
    fill_in_one_address(cct, ifa, cct->_conf->cluster_network, "cluster_addr");
  }

  freeifaddrs(ifa);
}

bool have_local_addr(CephContext *cct, const list<entity_addr_t>& ls, entity_addr_t *match)
{
  struct ifaddrs *ifa;
  int r = getifaddrs(&ifa);
  if (r < 0) {
    lderr(cct) << "unable to fetch interfaces and addresses: " << cpp_strerror(errno) << dendl;
    exit(1);
  }

  bool found = false;
  for (struct ifaddrs *addrs = ifa; addrs != NULL; addrs = addrs->ifa_next) {
    if (addrs->ifa_addr) {
      entity_addr_t a;
      a.set_sockaddr(addrs->ifa_addr);
      for (list<entity_addr_t>::const_iterator p = ls.begin(); p != ls.end(); ++p) {
        if (a.is_same_host(*p)) {
          *match = *p;
          found = true;
          goto out;
        }
      }
    }
  }

 out:
  freeifaddrs(ifa);
  return found;
}