1
#include "source/common/upstream/default_local_address_selector_factory.h"
2

            
3
#include "source/common/upstream/default_local_address_selector.h"
4

            
5
namespace Envoy {
6
namespace Upstream {
7

            
8
namespace {
9
constexpr absl::string_view kDefaultLocalAddressSelectorName =
10
    "envoy.upstream.local_address_selector.default_local_address_selector";
11

            
12
absl::Status
13
validate(const std::vector<::Envoy::Upstream::UpstreamLocalAddress>& upstream_local_addresses,
14
18187
         absl::optional<std::string> cluster_name) {
15

            
16
18187
  if (upstream_local_addresses.empty()) {
17
2
    return absl::InvalidArgumentError(
18
2
        fmt::format("{}'s upstream binding config has no valid source address.",
19
2
                    !(cluster_name.has_value()) ? "Bootstrap"
20
2
                                                : fmt::format("Cluster {}", cluster_name.value())));
21
2
  }
22

            
23
18185
  if (upstream_local_addresses.size() > 2) {
24
4
    return absl::InvalidArgumentError(fmt::format(
25
4
        "{}'s upstream binding config has more than one extra/additional source addresses. Only "
26
4
        "one extra/additional source can be supported in BindConfig's "
27
4
        "extra_source_addresses/additional_source_addresses field",
28
4
        !(cluster_name.has_value()) ? "Bootstrap"
29
4
                                    : fmt::format("Cluster {}", cluster_name.value())));
30
4
  }
31
  // If we have exactly one upstream address, it needs to have a valid IP
32
  // version if non-null. This is enforced by the fact that BindConfig only
33
  // allows socket address.
34
18181
  ASSERT(upstream_local_addresses.size() != 1 || upstream_local_addresses[0].address_ == nullptr ||
35
18181
         upstream_local_addresses[0].address_->ip() != nullptr);
36

            
37
  // If we have more than one upstream address, they need to have different IP versions.
38
18181
  if (upstream_local_addresses.size() == 2) {
39
12
    ASSERT(upstream_local_addresses[0].address_ != nullptr &&
40
12
           upstream_local_addresses[1].address_ != nullptr &&
41
12
           upstream_local_addresses[0].address_->ip() != nullptr &&
42
12
           upstream_local_addresses[1].address_->ip() != nullptr);
43

            
44
12
    if (upstream_local_addresses[0].address_->ip()->version() ==
45
12
        upstream_local_addresses[1].address_->ip()->version()) {
46
2
      return absl::InvalidArgumentError(fmt::format(
47
2
          "{}'s upstream binding config has two same IP version source addresses. Only two "
48
2
          "different IP version source addresses can be supported in BindConfig's source_address "
49
2
          "and extra_source_addresses/additional_source_addresses fields",
50
2
          !(cluster_name.has_value()) ? "Bootstrap"
51
2
                                      : fmt::format("Cluster {}", cluster_name.value())));
52
2
    }
53
12
  }
54
18179
  return absl::OkStatus();
55
18181
}
56

            
57
} // namespace
58

            
59
11981
std::string DefaultUpstreamLocalAddressSelectorFactory::name() const {
60
11981
  return std::string(kDefaultLocalAddressSelectorName);
61
11981
}
62

            
63
absl::StatusOr<UpstreamLocalAddressSelectorConstSharedPtr>
64
DefaultUpstreamLocalAddressSelectorFactory::createLocalAddressSelector(
65
    std::vector<::Envoy::Upstream::UpstreamLocalAddress> upstream_local_addresses,
66
18187
    absl::optional<std::string> cluster_name) const {
67
18187
  absl::Status status = validate(upstream_local_addresses, cluster_name);
68
18187
  if (!status.ok()) {
69
8
    return status;
70
8
  }
71
18179
  return std::make_shared<DefaultUpstreamLocalAddressSelector>(std::move(upstream_local_addresses));
72
18187
}
73

            
74
/**
75
 * Static registration for the default local address selector. @see RegisterFactory.
76
 */
77
REGISTER_FACTORY(DefaultUpstreamLocalAddressSelectorFactory, UpstreamLocalAddressSelectorFactory);
78

            
79
} // namespace Upstream
80
} // namespace Envoy