1
#pragma once
2

            
3
#include <string>
4
#include <vector>
5

            
6
#include "envoy/common/optref.h"
7
#include "envoy/config/cluster/v3/cluster.pb.h"
8
#include "envoy/config/core/v3/base.pb.h"
9
#include "envoy/config/typed_metadata.h"
10
#include "envoy/extensions/matching/common_inputs/transport_socket/v3/transport_socket_inputs.pb.h"
11
#include "envoy/matcher/matcher.h"
12
#include "envoy/network/address.h"
13
#include "envoy/network/connection.h"
14
#include "envoy/server/factory_context.h"
15
#include "envoy/server/transport_socket_config.h"
16
#include "envoy/stats/scope.h"
17
#include "envoy/stream_info/filter_state.h"
18
#include "envoy/upstream/host_description.h"
19
#include "envoy/upstream/transport_socket_matching_data.h"
20
#include "envoy/upstream/upstream.h"
21

            
22
#include "source/common/common/logger.h"
23
#include "source/common/config/metadata.h"
24
#include "source/common/config/well_known_names.h"
25
#include "source/common/protobuf/protobuf.h"
26
#include "source/extensions/matching/common_inputs/transport_socket/config.h"
27

            
28
#include "absl/container/flat_hash_map.h"
29
#include "xds/type/matcher/v3/matcher.pb.h"
30

            
31
namespace Envoy {
32
namespace Upstream {
33

            
34
// Action factory context for transport socket name actions - using the server factory context.
35
using TransportSocketActionFactoryContext = Server::Configuration::ServerFactoryContext;
36

            
37
class TransportSocketMatcherImpl : public Logger::Loggable<Logger::Id::upstream>,
38
                                   public TransportSocketMatcher {
39
public:
40
  static absl::StatusOr<std::unique_ptr<TransportSocketMatcherImpl>> create(
41
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
42
          socket_matches,
43
      Server::Configuration::TransportSocketFactoryContext& factory_context,
44
      Network::UpstreamTransportSocketFactoryPtr& default_factory, Stats::Scope& stats_scope);
45

            
46
  static absl::StatusOr<std::unique_ptr<TransportSocketMatcherImpl>> create(
47
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
48
          socket_matches,
49
      OptRef<const xds::type::matcher::v3::Matcher> transport_socket_matcher,
50
      Server::Configuration::TransportSocketFactoryContext& factory_context,
51
      Network::UpstreamTransportSocketFactoryPtr& default_factory, Stats::Scope& stats_scope);
52

            
53
  struct FactoryMatch {
54
    FactoryMatch(std::string match_name, Network::UpstreamTransportSocketFactoryPtr socket_factory,
55
                 TransportSocketMatchStats match_stats)
56
18243
        : name(std::move(match_name)), factory(std::move(socket_factory)), stats(match_stats) {}
57
    const std::string name;
58
    Network::UpstreamTransportSocketFactoryPtr factory;
59
    Config::Metadata::LabelSet label_set;
60
    mutable TransportSocketMatchStats stats;
61
  };
62

            
63
  MatchData resolve(const envoy::config::core::v3::Metadata* endpoint_metadata,
64
                    const envoy::config::core::v3::Metadata* locality_metadata,
65
                    Network::TransportSocketOptionsConstSharedPtr transport_socket_options =
66
                        nullptr) const override;
67

            
68
18152
  bool allMatchesSupportAlpn() const override {
69
18152
    if (!default_match_.factory->supportsAlpn()) {
70
16351
      return false;
71
16351
    }
72
1801
    for (const auto& match : matches_) {
73
6
      if (!match.factory->supportsAlpn()) {
74
5
        return false;
75
5
      }
76
6
    }
77
    // Also check transport sockets in the matcher-based map.
78
1796
    for (const auto& [name, factory] : transport_sockets_by_name_) {
79
      if (!factory->supportsAlpn()) {
80
        return false;
81
      }
82
    }
83
1796
    return true;
84
1796
  }
85

            
86
30046
  bool usesFilterState() const override { return uses_filter_state_; }
87

            
88
protected:
89
  TransportSocketMatcherImpl(
90
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
91
          socket_matches,
92
      Server::Configuration::TransportSocketFactoryContext& factory_context,
93
      Network::UpstreamTransportSocketFactoryPtr& default_factory, Stats::Scope& stats_scope,
94
      absl::Status& creation_status);
95

            
96
  TransportSocketMatcherImpl(
97
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
98
          socket_matches,
99
      OptRef<const xds::type::matcher::v3::Matcher> transport_socket_matcher,
100
      Server::Configuration::TransportSocketFactoryContext& factory_context,
101
      Network::UpstreamTransportSocketFactoryPtr& default_factory, Stats::Scope& stats_scope,
102
      absl::Status& creation_status);
103

            
104
  TransportSocketMatchStats generateStats(const std::string& prefix) const;
105

            
106
private:
107
  /**
108
   * Resolve the transport socket configuration using the matcher if available.
109
   * @param endpoint_metadata the metadata of the given host.
110
   * @param locality_metadata the metadata of the host's locality.
111
   * @param transport_socket_options optional transport socket options from downstream connection.
112
   * @return the match information of the transport socket selected.
113
   */
114
  MatchData
115
  resolveUsingMatcher(const envoy::config::core::v3::Metadata* endpoint_metadata,
116
                      const envoy::config::core::v3::Metadata* locality_metadata,
117
                      Network::TransportSocketOptionsConstSharedPtr transport_socket_options) const;
118

            
119
  /**
120
   * Setup legacy metadata-based socket matches.
121
   * @param socket_matches the socket matches configuration.
122
   * @param factory_context the factory context.
123
   * @param creation_status reference to store creation status.
124
   */
125
  void setupLegacySocketMatches(
126
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
127
          socket_matches,
128
      Server::Configuration::TransportSocketFactoryContext& factory_context,
129
      absl::Status& creation_status);
130

            
131
  /**
132
   * Setup transport socket matcher based on the provided configuration.
133
   * @param transport_socket_matcher the matcher configuration.
134
   * @param socket_matches the socket matches configuration.
135
   * @param factory_context the factory context.
136
   * @param creation_status reference to store creation status.
137
   */
138
  void setupTransportSocketMatcher(
139
      const xds::type::matcher::v3::Matcher& transport_socket_matcher,
140
      const Protobuf::RepeatedPtrField<envoy::config::cluster::v3::Cluster::TransportSocketMatch>&
141
          socket_matches,
142
      Server::Configuration::TransportSocketFactoryContext& factory_context,
143
      absl::Status& creation_status);
144

            
145
  Stats::Scope& stats_scope_;
146
  FactoryMatch default_match_;
147
  std::vector<FactoryMatch> matches_;
148

            
149
  // Matcher-based transport socket selection.
150
  using TransportSocketsByName =
151
      absl::flat_hash_map<std::string, Network::UpstreamTransportSocketFactoryPtr>;
152
  TransportSocketsByName transport_sockets_by_name_;
153
  // Pre-generated stats for matcher-selected transport sockets keyed by name.
154
  // Stats are created at config time to avoid calling generateStats() in the hot path.
155
  // Mutable because stats counters need to be incremented in the const resolve() method.
156
  mutable absl::flat_hash_map<std::string, TransportSocketMatchStats> matcher_stats_by_name_;
157
  std::unique_ptr<Matcher::MatchTree<Upstream::TransportSocketMatchingData>> matcher_;
158
  bool uses_filter_state_{false};
159
};
160

            
161
// Import action classes from the extension.
162
using TransportSocketNameAction =
163
    Extensions::Matching::CommonInputs::TransportSocket::TransportSocketNameAction;
164

            
165
} // namespace Upstream
166
} // namespace Envoy