/proc/self/cwd/source/common/runtime/runtime_features.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/runtime/runtime_features.h" |
2 | | |
3 | | #include "absl/flags/commandlineflag.h" |
4 | | #include "absl/flags/flag.h" |
5 | | #include "absl/strings/match.h" |
6 | | #include "absl/strings/str_replace.h" |
7 | | |
8 | | #define RUNTIME_GUARD(name) ABSL_FLAG(bool, name, true, ""); // NOLINT |
9 | | #define FALSE_RUNTIME_GUARD(name) ABSL_FLAG(bool, name, false, ""); // NOLINT |
10 | | |
11 | | // Add additional features here to enable the new code paths by default. |
12 | | // |
13 | | // Per documentation in CONTRIBUTING.md is expected that new high risk code paths be guarded |
14 | | // by runtime feature guards. If you add a guard of the form |
15 | | // RUNTIME_GUARD(envoy_reloadable_features_my_feature_name) |
16 | | // here you can guard code checking against "envoy.reloadable_features.my_feature_name". |
17 | | // Please note the swap of envoy_reloadable_features_ to envoy.reloadable_features.! |
18 | | // |
19 | | // if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.my_feature_name")) { |
20 | | // [new code path] |
21 | | // else { |
22 | | // [old_code_path] |
23 | | // } |
24 | | // |
25 | | // Runtime features are true by default, so the new code path is exercised. |
26 | | // To make a runtime feature false by default, use FALSE_RUNTIME_GUARD, and add |
27 | | // a TODO to change it to true. |
28 | | // |
29 | | // If issues are found that require a runtime feature to be disabled, it should be reported |
30 | | // ASAP by filing a bug on github. Overriding non-buggy code is strongly discouraged to avoid the |
31 | | // problem of the bugs being found after the old code path has been removed. |
32 | | RUNTIME_GUARD(envoy_reloadable_features_allow_alt_svc_for_ips); |
33 | | RUNTIME_GUARD(envoy_reloadable_features_boolean_to_string_fix); |
34 | | RUNTIME_GUARD(envoy_reloadable_features_check_switch_protocol_websocket_handshake); |
35 | | RUNTIME_GUARD(envoy_reloadable_features_conn_pool_delete_when_idle); |
36 | | RUNTIME_GUARD(envoy_reloadable_features_consistent_header_validation); |
37 | | RUNTIME_GUARD(envoy_reloadable_features_defer_processing_backedup_streams); |
38 | | RUNTIME_GUARD(envoy_reloadable_features_dfp_mixed_scheme); |
39 | | RUNTIME_GUARD(envoy_reloadable_features_disallow_quic_client_udp_mmsg); |
40 | | RUNTIME_GUARD(envoy_reloadable_features_dns_details); |
41 | | RUNTIME_GUARD(envoy_reloadable_features_dns_nodata_noname_is_success); |
42 | | RUNTIME_GUARD(envoy_reloadable_features_dns_reresolve_on_eai_again); |
43 | | RUNTIME_GUARD(envoy_reloadable_features_edf_lb_host_scheduler_init_fix); |
44 | | RUNTIME_GUARD(envoy_reloadable_features_edf_lb_locality_scheduler_init_fix); |
45 | | RUNTIME_GUARD(envoy_reloadable_features_enable_compression_bomb_protection); |
46 | | RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms); |
47 | | RUNTIME_GUARD(envoy_reloadable_features_exclude_host_in_eds_status_draining); |
48 | | RUNTIME_GUARD(envoy_reloadable_features_ext_proc_timeout_error); |
49 | | RUNTIME_GUARD(envoy_reloadable_features_extend_h3_accept_untrusted); |
50 | | RUNTIME_GUARD(envoy_reloadable_features_gcp_authn_use_fixed_url); |
51 | | RUNTIME_GUARD(envoy_reloadable_features_getaddrinfo_num_retries); |
52 | | RUNTIME_GUARD(envoy_reloadable_features_grpc_side_stream_flow_control); |
53 | | RUNTIME_GUARD(envoy_reloadable_features_http1_balsa_delay_reset); |
54 | | RUNTIME_GUARD(envoy_reloadable_features_http1_balsa_disallow_lone_cr_in_chunk_extension); |
55 | | // Ignore the automated "remove this flag" issue: we should keep this for 1 year. |
56 | | RUNTIME_GUARD(envoy_reloadable_features_http1_use_balsa_parser); |
57 | | RUNTIME_GUARD(envoy_reloadable_features_http2_discard_host_header); |
58 | | // Ignore the automated "remove this flag" issue: we should keep this for 1 year. |
59 | | RUNTIME_GUARD(envoy_reloadable_features_http2_use_oghttp2); |
60 | | RUNTIME_GUARD(envoy_reloadable_features_http2_use_visitor_for_data); |
61 | | RUNTIME_GUARD(envoy_reloadable_features_http3_happy_eyeballs); |
62 | | RUNTIME_GUARD(envoy_reloadable_features_http3_remove_empty_trailers); |
63 | | RUNTIME_GUARD(envoy_reloadable_features_http_filter_avoid_reentrant_local_reply); |
64 | | // Delay deprecation and decommission until UHV is enabled. |
65 | | RUNTIME_GUARD(envoy_reloadable_features_http_reject_path_with_fragment); |
66 | | RUNTIME_GUARD(envoy_reloadable_features_http_route_connect_proxy_by_default); |
67 | | RUNTIME_GUARD(envoy_reloadable_features_internal_authority_header_validator); |
68 | | RUNTIME_GUARD(envoy_reloadable_features_jwt_authn_remove_jwt_from_query_params); |
69 | | RUNTIME_GUARD(envoy_reloadable_features_jwt_authn_validate_uri); |
70 | | RUNTIME_GUARD(envoy_reloadable_features_lua_flow_control_while_http_call); |
71 | | RUNTIME_GUARD(envoy_reloadable_features_mmdb_files_reload_enabled); |
72 | | RUNTIME_GUARD(envoy_reloadable_features_no_extension_lookup_by_name); |
73 | | RUNTIME_GUARD(envoy_reloadable_features_no_timer_based_rate_limit_token_bucket); |
74 | | RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout); |
75 | | RUNTIME_GUARD(envoy_reloadable_features_prefer_ipv6_dns_on_macos); |
76 | | RUNTIME_GUARD(envoy_reloadable_features_proxy_104); |
77 | | RUNTIME_GUARD(envoy_reloadable_features_proxy_ssl_port); |
78 | | RUNTIME_GUARD(envoy_reloadable_features_proxy_status_mapping_more_core_response_flags); |
79 | | RUNTIME_GUARD(envoy_reloadable_features_quic_connect_client_udp_sockets); |
80 | | RUNTIME_GUARD(envoy_reloadable_features_quic_receive_ecn); |
81 | | // Ignore the automated "remove this flag" issue: we should keep this for 1 year. Confirm with |
82 | | // @danzh2010 or @RyanTheOptimist before removing. |
83 | | RUNTIME_GUARD(envoy_reloadable_features_quic_send_server_preferred_address_to_all_clients); |
84 | | RUNTIME_GUARD(envoy_reloadable_features_quic_support_certificate_compression); |
85 | | RUNTIME_GUARD(envoy_reloadable_features_quic_upstream_reads_fixed_number_packets); |
86 | | RUNTIME_GUARD(envoy_reloadable_features_quic_upstream_socket_use_address_cache_for_read); |
87 | | RUNTIME_GUARD(envoy_reloadable_features_reject_invalid_yaml); |
88 | | RUNTIME_GUARD(envoy_reloadable_features_report_stream_reset_error_code); |
89 | | RUNTIME_GUARD(envoy_reloadable_features_sanitize_http2_headers_without_nghttp2); |
90 | | RUNTIME_GUARD(envoy_reloadable_features_sanitize_te); |
91 | | RUNTIME_GUARD(envoy_reloadable_features_send_local_reply_when_no_buffer_and_upstream_request); |
92 | | RUNTIME_GUARD(envoy_reloadable_features_skip_dns_lookup_for_proxied_requests); |
93 | | RUNTIME_GUARD(envoy_reloadable_features_strict_duration_validation); |
94 | | RUNTIME_GUARD(envoy_reloadable_features_tcp_tunneling_send_downstream_fin_on_upstream_trailers); |
95 | | RUNTIME_GUARD(envoy_reloadable_features_test_feature_true); |
96 | | RUNTIME_GUARD(envoy_reloadable_features_udp_socket_apply_aggregated_read_limit); |
97 | | RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding); |
98 | | RUNTIME_GUARD(envoy_reloadable_features_upstream_remote_address_use_connection); |
99 | | RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs); |
100 | | RUNTIME_GUARD(envoy_reloadable_features_use_filter_manager_state_for_downstream_end_stream); |
101 | | RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials); |
102 | | RUNTIME_GUARD(envoy_reloadable_features_use_route_host_mutation_for_auto_sni_san); |
103 | | RUNTIME_GUARD(envoy_reloadable_features_use_typed_metadata_in_proxy_protocol_listener); |
104 | | RUNTIME_GUARD(envoy_reloadable_features_validate_connect); |
105 | | RUNTIME_GUARD(envoy_reloadable_features_validate_grpc_header_before_log_grpc_status); |
106 | | RUNTIME_GUARD(envoy_reloadable_features_validate_upstream_headers); |
107 | | RUNTIME_GUARD(envoy_reloadable_features_xdstp_path_avoid_colon_encoding); |
108 | | RUNTIME_GUARD(envoy_restart_features_allow_client_socket_creation_failure); |
109 | | RUNTIME_GUARD(envoy_restart_features_allow_slot_destroy_on_worker_threads); |
110 | | RUNTIME_GUARD(envoy_restart_features_fix_dispatcher_approximate_now); |
111 | | RUNTIME_GUARD(envoy_restart_features_quic_handle_certs_with_shared_tls_code); |
112 | | RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads); |
113 | | RUNTIME_GUARD(envoy_restart_features_use_fast_protobuf_hash); |
114 | | |
115 | | // Begin false flags. Most of them should come with a TODO to flip true. |
116 | | |
117 | | // Execution context is optional and must be enabled explicitly. |
118 | | // See https://github.com/envoyproxy/envoy/issues/32012. |
119 | | FALSE_RUNTIME_GUARD(envoy_restart_features_enable_execution_context); |
120 | | // Sentinel and test flag. |
121 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_test_feature_false); |
122 | | // TODO(paul-r-gall) Make this enabled by default after additional soak time. |
123 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_streaming_shadow); |
124 | | // TODO(adisuissa) reset to true to enable unified mux by default |
125 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_unified_mux); |
126 | | // Used to track if runtime is initialized. |
127 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized); |
128 | | // TODO(mattklein123): Flip this to true and/or remove completely once verified by Envoy Mobile. |
129 | | // TODO(mattklein123): Also unit test this if this sticks and this becomes the default for Apple & |
130 | | // Android. |
131 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_always_use_v6); |
132 | | // TODO(vikaschoudhary16) flip this to true only after all the |
133 | | // TcpProxy::Filter::HttpStreamDecoderFilterCallbacks are implemented or commented as unnecessary |
134 | | FALSE_RUNTIME_GUARD(envoy_restart_features_upstream_http_filters_with_tcp_proxy); |
135 | | // TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag. |
136 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all); |
137 | | // TODO(#10646) change to true when UHV is sufficiently tested |
138 | | // For more information about Universal Header Validation, please see |
139 | | // https://github.com/envoyproxy/envoy/issues/10646 |
140 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_universal_header_validator); |
141 | | // TODO(pksohn): enable after canarying fix for https://github.com/envoyproxy/envoy/issues/29930 |
142 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_defer_logging_to_ack_listener); |
143 | | // TODO(#33474) removed it once GRO packet dropping is fixed. |
144 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_prefer_quic_client_udp_gro); |
145 | | // TODO(alyssar) evaluate and either make this a config knob or remove. |
146 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_reresolve_null_addresses); |
147 | | // TODO(alyssar) evaluate and either make this a config knob or remove. |
148 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_reresolve_if_no_connections); |
149 | | // TODO(adisuissa): flip to true after this is out of alpha mode. |
150 | | FALSE_RUNTIME_GUARD(envoy_restart_features_xds_failover_support); |
151 | | // TODO(fredyw): evaluate and either make this a config knob or remove. |
152 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_dns_cache_set_ip_version_to_remove); |
153 | | // TODO(alyssawilk): evaluate and make this a config knob or remove. |
154 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_reset_brokenness_on_nework_change); |
155 | | |
156 | | // A flag to set the maximum TLS version for google_grpc client to TLS1.2, when needed for |
157 | | // compliance restrictions. |
158 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_google_grpc_disable_tls_13); |
159 | | |
160 | | // TODO(yanavlasov): Flip to true after prod testing. |
161 | | // Controls whether a stream stays open when HTTP/2 or HTTP/3 upstream half closes |
162 | | // before downstream. |
163 | | FALSE_RUNTIME_GUARD(envoy_reloadable_features_allow_multiplexed_upstream_half_close); |
164 | | |
165 | | // Block of non-boolean flags. Use of int flags is deprecated. Do not add more. |
166 | | ABSL_FLAG(uint64_t, re2_max_program_size_error_level, 100, ""); // NOLINT |
167 | | ABSL_FLAG(uint64_t, re2_max_program_size_warn_level, // NOLINT |
168 | | std::numeric_limits<uint32_t>::max(), ""); // NOLINT |
169 | | |
170 | | namespace Envoy { |
171 | | namespace Runtime { |
172 | | namespace { |
173 | | |
174 | 4.84k | std::string swapPrefix(std::string name) { |
175 | 4.84k | return absl::StrReplaceAll(name, {{"envoy_", "envoy."}, {"features_", "features."}}); |
176 | 4.84k | } |
177 | | |
178 | | } // namespace |
179 | | |
180 | | // This is a singleton class to map Envoy style flag names to absl flags |
181 | | class RuntimeFeatures { |
182 | | public: |
183 | | RuntimeFeatures(); |
184 | | |
185 | | // Get the command line flag corresponding to the Envoy style feature name, or |
186 | | // nullptr if it is not a registered flag. |
187 | 4.91M | absl::CommandLineFlag* getFlag(absl::string_view feature) const { |
188 | 4.91M | auto it = all_features_.find(feature); |
189 | 4.91M | if (it == all_features_.end()) { |
190 | 94.0k | return nullptr; |
191 | 94.0k | } |
192 | 4.82M | return it->second; |
193 | 4.91M | } |
194 | | |
195 | | private: |
196 | | absl::flat_hash_map<std::string, absl::CommandLineFlag*> all_features_; |
197 | | }; |
198 | | |
199 | | using RuntimeFeaturesDefaults = ConstSingleton<RuntimeFeatures>; |
200 | | |
201 | 51 | RuntimeFeatures::RuntimeFeatures() { |
202 | 51 | absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> flags = absl::GetAllFlags(); |
203 | 10.4k | for (auto& it : flags) { |
204 | 10.4k | absl::string_view name = it.second->Name(); |
205 | 10.4k | if ((!absl::StartsWith(name, "envoy_reloadable_features_") && |
206 | 10.4k | !absl::StartsWith(name, "envoy_restart_features_")) || |
207 | 10.4k | !it.second->TryGet<bool>().has_value()) { |
208 | 5.62k | continue; |
209 | 5.62k | } |
210 | 4.84k | std::string envoy_name = swapPrefix(std::string(name)); |
211 | 4.84k | all_features_.emplace(envoy_name, it.second); |
212 | 4.84k | } |
213 | 51 | } |
214 | | |
215 | 8.23k | bool hasRuntimePrefix(absl::string_view feature) { |
216 | | // Track Envoy reloadable and restart features, excluding synthetic QUIC flags |
217 | | // which are not tracked in the list below. |
218 | 8.23k | return (absl::StartsWith(feature, "envoy.reloadable_features.") && |
219 | 8.23k | !absl::StartsWith(feature, "envoy.reloadable_features.FLAGS_envoy_quic")) || |
220 | 8.23k | absl::StartsWith(feature, "envoy.restart_features."); |
221 | 8.23k | } |
222 | | |
223 | 137k | bool isRuntimeFeature(absl::string_view feature) { |
224 | 137k | return RuntimeFeaturesDefaults::get().getFlag(feature) != nullptr; |
225 | 137k | } |
226 | | |
227 | 4.63M | bool runtimeFeatureEnabled(absl::string_view feature) { |
228 | 4.63M | absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(feature); |
229 | 4.63M | if (flag == nullptr) { |
230 | 0 | IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", feature)); |
231 | 0 | return false; |
232 | 0 | } |
233 | | // We validate in map creation that the flag is a boolean. |
234 | 4.63M | return flag->TryGet<bool>().value(); |
235 | 4.63M | } |
236 | | |
237 | 17.5k | uint64_t getInteger(absl::string_view feature, uint64_t default_value) { |
238 | | // DO NOT ADD MORE FLAGS HERE. This function deprecated. |
239 | 17.5k | if (absl::StartsWith(feature, "re2.")) { |
240 | 17.5k | if (feature == "re2.max_program_size.error_level") { |
241 | 8.77k | return absl::GetFlag(FLAGS_re2_max_program_size_error_level); |
242 | 8.77k | } else if (feature == "re2.max_program_size.warn_level") { |
243 | 8.77k | return absl::GetFlag(FLAGS_re2_max_program_size_warn_level); |
244 | 8.77k | } |
245 | 17.5k | } |
246 | 0 | IS_ENVOY_BUG(absl::StrCat("requested an unsupported integer ", feature)); |
247 | 0 | return default_value; |
248 | 0 | } |
249 | | |
250 | 97.5k | void markRuntimeInitialized() { |
251 | 97.5k | maybeSetRuntimeGuard("envoy.reloadable_features.runtime_initialized", true); |
252 | 97.5k | } |
253 | | |
254 | 37.6k | bool isRuntimeInitialized() { |
255 | 37.6k | return runtimeFeatureEnabled("envoy.reloadable_features.runtime_initialized"); |
256 | 37.6k | } |
257 | | |
258 | 139k | void maybeSetRuntimeGuard(absl::string_view name, bool value) { |
259 | 139k | absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(name); |
260 | 139k | if (flag == nullptr) { |
261 | 0 | IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", name)); |
262 | 0 | return; |
263 | 0 | } |
264 | 139k | std::string err; |
265 | 139k | flag->ParseFrom(value ? "true" : "false", &err); |
266 | 139k | } |
267 | | |
268 | 4.08k | void maybeSetDeprecatedInts(absl::string_view name, uint32_t value) { |
269 | 4.08k | if (!absl::StartsWith(name, "envoy.") && !absl::StartsWith(name, "re2.")) { |
270 | 3.80k | return; |
271 | 3.80k | } |
272 | | |
273 | | // DO NOT ADD MORE FLAGS HERE. This function deprecated. |
274 | 285 | else if (name == "re2.max_program_size.error_level") { |
275 | 0 | absl::SetFlag(&FLAGS_re2_max_program_size_error_level, value); |
276 | 285 | } else if (name == "re2.max_program_size.warn_level") { |
277 | 0 | absl::SetFlag(&FLAGS_re2_max_program_size_warn_level, value); |
278 | 0 | } |
279 | 4.08k | } |
280 | | |
281 | | } // namespace Runtime |
282 | | } // namespace Envoy |