1
#pragma once
2

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

            
7
#include "envoy/common/optref.h"
8
#include "envoy/stats/scope.h"
9
#include "envoy/stats/stats.h"
10

            
11
#include "source/common/common/logger.h"
12
#include "source/common/stats/utility.h"
13
#include "source/extensions/dynamic_modules/abi/abi.h"
14
#include "source/extensions/dynamic_modules/dynamic_modules.h"
15

            
16
namespace Envoy {
17
namespace Extensions {
18
namespace LoadBalancingPolicies {
19
namespace DynamicModules {
20

            
21
// The default custom stat namespace which prepends all user-defined metrics.
22
// This can be overridden via the ``metrics_namespace`` field in ``DynamicModuleConfig``.
23
constexpr absl::string_view DefaultMetricsNamespace = "dynamicmodulescustom";
24

            
25
class DynamicModuleLbConfig;
26
using DynamicModuleLbConfigSharedPtr = std::shared_ptr<DynamicModuleLbConfig>;
27

            
28
/**
29
 * Function pointer types for the load balancer ABI functions.
30
 */
31
using OnLbConfigNewType = decltype(&envoy_dynamic_module_on_lb_config_new);
32
using OnLbConfigDestroyType = decltype(&envoy_dynamic_module_on_lb_config_destroy);
33
using OnLbNewType = decltype(&envoy_dynamic_module_on_lb_new);
34
using OnLbChooseHostType = decltype(&envoy_dynamic_module_on_lb_choose_host);
35
using OnLbOnHostMembershipUpdateType =
36
    decltype(&envoy_dynamic_module_on_lb_on_host_membership_update);
37
using OnLbDestroyType = decltype(&envoy_dynamic_module_on_lb_destroy);
38

            
39
/**
40
 * Configuration for a dynamic module load balancer. This holds the loaded dynamic module and
41
 * the resolved function pointers for the ABI.
42
 */
43
class DynamicModuleLbConfig : public Logger::Loggable<Logger::Id::dynamic_modules> {
44
public:
45
  /**
46
   * Creates a new DynamicModuleLbConfig.
47
   *
48
   * @param lb_policy_name the name identifying the load balancer implementation in the module.
49
   * @param lb_config the configuration bytes to pass to the module.
50
   * @param metrics_namespace the namespace prefix for metrics emitted by this module.
51
   * @param dynamic_module the loaded dynamic module.
52
   * @param stats_scope the stats scope for creating custom metrics.
53
   * @return a shared pointer to the config, or an error status.
54
   */
55
  static absl::StatusOr<DynamicModuleLbConfigSharedPtr>
56
  create(const std::string& lb_policy_name, const std::string& lb_config,
57
         const std::string& metrics_namespace,
58
         Envoy::Extensions::DynamicModules::DynamicModulePtr dynamic_module,
59
         Stats::Scope& stats_scope);
60

            
61
  ~DynamicModuleLbConfig();
62

            
63
  // Function pointers resolved from the dynamic module.
64
  OnLbConfigNewType on_config_new_;
65
  OnLbConfigDestroyType on_config_destroy_;
66
  OnLbNewType on_lb_new_;
67
  OnLbChooseHostType on_choose_host_;
68
  OnLbOnHostMembershipUpdateType on_host_membership_update_;
69
  OnLbDestroyType on_lb_destroy_;
70

            
71
  // The in-module configuration pointer.
72
  envoy_dynamic_module_type_lb_config_module_ptr in_module_config_;
73

            
74
  // ----------------------------- Metrics Support -----------------------------
75

            
76
  class ModuleCounterHandle {
77
  public:
78
3
    ModuleCounterHandle(Stats::Counter& counter) : counter_(counter) {}
79
4
    void add(uint64_t value) const { counter_.add(value); }
80

            
81
  private:
82
    Stats::Counter& counter_;
83
  };
84

            
85
  class ModuleCounterVecHandle {
86
  public:
87
    ModuleCounterVecHandle(Stats::StatName name, Stats::StatNameVec label_names)
88
2
        : name_(name), label_names_(label_names) {}
89
5
    const Stats::StatNameVec& getLabelNames() const { return label_names_; }
90
2
    void add(Stats::Scope& scope, Stats::StatNameTagVectorOptConstRef tags, uint64_t amount) const {
91
2
      ASSERT(tags.has_value());
92
2
      Stats::Utility::counterFromElements(scope, {name_}, tags).add(amount);
93
2
    }
94

            
95
  private:
96
    Stats::StatName name_;
97
    Stats::StatNameVec label_names_;
98
  };
99

            
100
  class ModuleGaugeHandle {
101
  public:
102
1
    ModuleGaugeHandle(Stats::Gauge& gauge) : gauge_(gauge) {}
103
1
    void add(uint64_t value) const { gauge_.add(value); }
104
1
    void sub(uint64_t value) const { gauge_.sub(value); }
105
1
    void set(uint64_t value) const { gauge_.set(value); }
106

            
107
  private:
108
    Stats::Gauge& gauge_;
109
  };
110

            
111
  class ModuleGaugeVecHandle {
112
  public:
113
    ModuleGaugeVecHandle(Stats::StatName name, Stats::StatNameVec label_names,
114
                         Stats::Gauge::ImportMode import_mode)
115
3
        : name_(name), label_names_(label_names), import_mode_(import_mode) {}
116
9
    const Stats::StatNameVec& getLabelNames() const { return label_names_; }
117
1
    void add(Stats::Scope& scope, Stats::StatNameTagVectorOptConstRef tags, uint64_t amount) const {
118
1
      ASSERT(tags.has_value());
119
1
      Stats::Utility::gaugeFromElements(scope, {name_}, import_mode_, tags).add(amount);
120
1
    }
121
1
    void sub(Stats::Scope& scope, Stats::StatNameTagVectorOptConstRef tags, uint64_t amount) const {
122
1
      ASSERT(tags.has_value());
123
1
      Stats::Utility::gaugeFromElements(scope, {name_}, import_mode_, tags).sub(amount);
124
1
    }
125
1
    void set(Stats::Scope& scope, Stats::StatNameTagVectorOptConstRef tags, uint64_t amount) const {
126
1
      ASSERT(tags.has_value());
127
1
      Stats::Utility::gaugeFromElements(scope, {name_}, import_mode_, tags).set(amount);
128
1
    }
129

            
130
  private:
131
    Stats::StatName name_;
132
    Stats::StatNameVec label_names_;
133
    Stats::Gauge::ImportMode import_mode_;
134
  };
135

            
136
  class ModuleHistogramHandle {
137
  public:
138
1
    ModuleHistogramHandle(Stats::Histogram& histogram) : histogram_(histogram) {}
139
1
    void recordValue(uint64_t value) const { histogram_.recordValue(value); }
140

            
141
  private:
142
    Stats::Histogram& histogram_;
143
  };
144

            
145
  class ModuleHistogramVecHandle {
146
  public:
147
    ModuleHistogramVecHandle(Stats::StatName name, Stats::StatNameVec label_names,
148
                             Stats::Histogram::Unit unit)
149
2
        : name_(name), label_names_(label_names), unit_(unit) {}
150
3
    const Stats::StatNameVec& getLabelNames() const { return label_names_; }
151
    void recordValue(Stats::Scope& scope, Stats::StatNameTagVectorOptConstRef tags,
152
1
                     uint64_t value) const {
153
1
      ASSERT(tags.has_value());
154
1
      Stats::Utility::histogramFromElements(scope, {name_}, unit_, tags).recordValue(value);
155
1
    }
156

            
157
  private:
158
    Stats::StatName name_;
159
    Stats::StatNameVec label_names_;
160
    Stats::Histogram::Unit unit_;
161
  };
162

            
163
// We use 1-based IDs for the metrics in the ABI, so we need to convert them to 0-based indices
164
// for our internal storage. These helper functions do that conversion.
165
26
#define ID_TO_INDEX(id) ((id) - 1)
166

            
167
3
  size_t addCounter(ModuleCounterHandle&& counter) {
168
3
    counters_.push_back(std::move(counter));
169
3
    return counters_.size();
170
3
  }
171
2
  size_t addCounterVec(ModuleCounterVecHandle&& counter) {
172
2
    counter_vecs_.push_back(std::move(counter));
173
2
    return counter_vecs_.size();
174
2
  }
175

            
176
1
  size_t addGauge(ModuleGaugeHandle&& gauge) {
177
1
    gauges_.push_back(std::move(gauge));
178
1
    return gauges_.size();
179
1
  }
180
3
  size_t addGaugeVec(ModuleGaugeVecHandle&& gauge) {
181
3
    gauge_vecs_.push_back(std::move(gauge));
182
3
    return gauge_vecs_.size();
183
3
  }
184

            
185
1
  size_t addHistogram(ModuleHistogramHandle&& histogram) {
186
1
    histograms_.push_back(std::move(histogram));
187
1
    return histograms_.size();
188
1
  }
189
2
  size_t addHistogramVec(ModuleHistogramVecHandle&& histogram) {
190
2
    histogram_vecs_.push_back(std::move(histogram));
191
2
    return histogram_vecs_.size();
192
2
  }
193

            
194
7
  OptRef<const ModuleCounterHandle> getCounterById(size_t id) const {
195
7
    if (id == 0 || id > counters_.size()) {
196
3
      return {};
197
3
    }
198
4
    return counters_[ID_TO_INDEX(id)];
199
7
  }
200
7
  OptRef<const ModuleCounterVecHandle> getCounterVecById(size_t id) const {
201
7
    if (id == 0 || id > counter_vecs_.size()) {
202
3
      return {};
203
3
    }
204
4
    return counter_vecs_[ID_TO_INDEX(id)];
205
7
  }
206

            
207
11
  OptRef<const ModuleGaugeHandle> getGaugeById(size_t id) const {
208
11
    if (id == 0 || id > gauges_.size()) {
209
8
      return {};
210
8
    }
211
3
    return gauges_[ID_TO_INDEX(id)];
212
11
  }
213
17
  OptRef<const ModuleGaugeVecHandle> getGaugeVecById(size_t id) const {
214
17
    if (id == 0 || id > gauge_vecs_.size()) {
215
7
      return {};
216
7
    }
217
10
    return gauge_vecs_[ID_TO_INDEX(id)];
218
17
  }
219

            
220
5
  OptRef<const ModuleHistogramHandle> getHistogramById(size_t id) const {
221
5
    if (id == 0 || id > histograms_.size()) {
222
4
      return {};
223
4
    }
224
1
    return histograms_[ID_TO_INDEX(id)];
225
5
  }
226
7
  OptRef<const ModuleHistogramVecHandle> getHistogramVecById(size_t id) const {
227
7
    if (id == 0 || id > histogram_vecs_.size()) {
228
3
      return {};
229
3
    }
230
4
    return histogram_vecs_[ID_TO_INDEX(id)];
231
7
  }
232

            
233
#undef ID_TO_INDEX
234

            
235
  const Stats::ScopeSharedPtr stats_scope_;
236
  Stats::StatNamePool stat_name_pool_;
237

            
238
private:
239
  DynamicModuleLbConfig(const std::string& lb_policy_name, const std::string& lb_config,
240
                        const std::string& metrics_namespace,
241
                        Envoy::Extensions::DynamicModules::DynamicModulePtr dynamic_module,
242
                        Stats::Scope& stats_scope);
243

            
244
  const std::string lb_policy_name_;
245
  const std::string lb_config_;
246
  Envoy::Extensions::DynamicModules::DynamicModulePtr dynamic_module_;
247

            
248
  std::vector<ModuleCounterHandle> counters_;
249
  std::vector<ModuleCounterVecHandle> counter_vecs_;
250
  std::vector<ModuleGaugeHandle> gauges_;
251
  std::vector<ModuleGaugeVecHandle> gauge_vecs_;
252
  std::vector<ModuleHistogramHandle> histograms_;
253
  std::vector<ModuleHistogramVecHandle> histogram_vecs_;
254
};
255

            
256
} // namespace DynamicModules
257
} // namespace LoadBalancingPolicies
258
} // namespace Extensions
259
} // namespace Envoy