Line data Source code
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_absolute_url_with_mixed_scheme); 33 : RUNTIME_GUARD(envoy_reloadable_features_append_xfh_idempotent); 34 : RUNTIME_GUARD(envoy_reloadable_features_avoid_zombie_streams); 35 : RUNTIME_GUARD(envoy_reloadable_features_check_mep_on_first_eject); 36 : RUNTIME_GUARD(envoy_reloadable_features_conn_pool_delete_when_idle); 37 : RUNTIME_GUARD(envoy_reloadable_features_convert_legacy_lb_config); 38 : RUNTIME_GUARD(envoy_reloadable_features_copy_response_code_to_downstream_stream_info); 39 : RUNTIME_GUARD(envoy_reloadable_features_count_unused_mapped_pages_as_free); 40 : RUNTIME_GUARD(envoy_reloadable_features_defer_processing_backedup_streams); 41 : RUNTIME_GUARD(envoy_reloadable_features_detect_and_raise_rst_tcp_connection); 42 : RUNTIME_GUARD(envoy_reloadable_features_dfp_mixed_scheme); 43 : RUNTIME_GUARD(envoy_reloadable_features_dns_cache_set_first_resolve_complete); 44 : RUNTIME_GUARD(envoy_reloadable_features_enable_aws_credentials_file); 45 : RUNTIME_GUARD(envoy_reloadable_features_enable_compression_bomb_protection); 46 : RUNTIME_GUARD(envoy_reloadable_features_enable_connect_udp_support); 47 : RUNTIME_GUARD(envoy_reloadable_features_enable_intermediate_ca); 48 : RUNTIME_GUARD(envoy_reloadable_features_enable_zone_routing_different_zone_counts); 49 : RUNTIME_GUARD(envoy_reloadable_features_ext_authz_http_send_original_xff); 50 : RUNTIME_GUARD(envoy_reloadable_features_grpc_http1_reverse_bridge_handle_empty_response); 51 : RUNTIME_GUARD(envoy_reloadable_features_handle_uppercase_scheme); 52 : RUNTIME_GUARD(envoy_reloadable_features_hmac_base64_encoding_only); 53 : RUNTIME_GUARD(envoy_reloadable_features_http1_allow_codec_error_response_after_1xx_headers); 54 : RUNTIME_GUARD(envoy_reloadable_features_http1_connection_close_header_in_redirect); 55 : RUNTIME_GUARD(envoy_reloadable_features_http1_use_balsa_parser); 56 : RUNTIME_GUARD(envoy_reloadable_features_http2_decode_metadata_with_quiche); 57 : RUNTIME_GUARD(envoy_reloadable_features_http2_discard_host_header); 58 : RUNTIME_GUARD(envoy_reloadable_features_http2_use_oghttp2); 59 : RUNTIME_GUARD(envoy_reloadable_features_http2_validate_authority_with_quiche); 60 : RUNTIME_GUARD(envoy_reloadable_features_http_allow_partial_urls_in_referer); 61 : RUNTIME_GUARD(envoy_reloadable_features_http_filter_avoid_reentrant_local_reply); 62 : // Delay deprecation and decommission until UHV is enabled. 63 : RUNTIME_GUARD(envoy_reloadable_features_http_reject_path_with_fragment); 64 : RUNTIME_GUARD(envoy_reloadable_features_immediate_response_use_filter_mutation_rule); 65 : RUNTIME_GUARD(envoy_reloadable_features_initialize_upstream_filters); 66 : RUNTIME_GUARD(envoy_reloadable_features_keep_endpoint_active_hc_status_on_locality_update); 67 : RUNTIME_GUARD(envoy_reloadable_features_locality_routing_use_new_routing_logic); 68 : RUNTIME_GUARD(envoy_reloadable_features_lowercase_scheme); 69 : RUNTIME_GUARD(envoy_reloadable_features_no_downgrade_to_canonical_name); 70 : RUNTIME_GUARD(envoy_reloadable_features_no_extension_lookup_by_name); 71 : RUNTIME_GUARD(envoy_reloadable_features_no_full_scan_certs_on_sni_mismatch); 72 : RUNTIME_GUARD(envoy_reloadable_features_normalize_host_for_preresolve_dfp_dns); 73 : RUNTIME_GUARD(envoy_reloadable_features_oauth_make_token_cookie_httponly); 74 : RUNTIME_GUARD(envoy_reloadable_features_oauth_use_standard_max_age_value); 75 : RUNTIME_GUARD(envoy_reloadable_features_oauth_use_url_encoding); 76 : RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout); 77 : RUNTIME_GUARD(envoy_reloadable_features_overload_manager_error_unknown_action); 78 : RUNTIME_GUARD(envoy_reloadable_features_proxy_status_upstream_request_timeout); 79 : RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf); 80 : RUNTIME_GUARD(envoy_reloadable_features_sanitize_te); 81 : RUNTIME_GUARD(envoy_reloadable_features_send_header_raw_value); 82 : RUNTIME_GUARD(envoy_reloadable_features_skip_dns_lookup_for_proxied_requests); 83 : RUNTIME_GUARD(envoy_reloadable_features_ssl_transport_failure_reason_format); 84 : RUNTIME_GUARD(envoy_reloadable_features_stateful_session_encode_ttl_in_cookie); 85 : RUNTIME_GUARD(envoy_reloadable_features_stop_decode_metadata_on_local_reply); 86 : RUNTIME_GUARD(envoy_reloadable_features_test_feature_true); 87 : RUNTIME_GUARD(envoy_reloadable_features_thrift_allow_negative_field_ids); 88 : RUNTIME_GUARD(envoy_reloadable_features_thrift_connection_draining); 89 : RUNTIME_GUARD(envoy_reloadable_features_token_passed_entirely); 90 : RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding); 91 : RUNTIME_GUARD(envoy_reloadable_features_upstream_allow_connect_with_2xx); 92 : RUNTIME_GUARD(envoy_reloadable_features_upstream_wait_for_response_headers_before_disabling_read); 93 : RUNTIME_GUARD(envoy_reloadable_features_use_cluster_cache_for_alt_protocols_filter); 94 : RUNTIME_GUARD(envoy_reloadable_features_use_http3_header_normalisation); 95 : RUNTIME_GUARD(envoy_reloadable_features_validate_connect); 96 : RUNTIME_GUARD(envoy_reloadable_features_validate_grpc_header_before_log_grpc_status); 97 : RUNTIME_GUARD(envoy_reloadable_features_validate_upstream_headers); 98 : RUNTIME_GUARD(envoy_restart_features_send_goaway_for_premature_rst_streams); 99 : RUNTIME_GUARD(envoy_restart_features_udp_read_normalize_addresses); 100 : 101 : // Begin false flags. These should come with a TODO to flip true. 102 : // Sentinel and test flag. 103 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_test_feature_false); 104 : // TODO(paul-r-gall) Make this enabled by default after additional soak time. 105 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_streaming_shadow); 106 : // TODO(adisuissa) reset to true to enable unified mux by default 107 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_unified_mux); 108 : // Used to track if runtime is initialized. 109 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized); 110 : // TODO(mattklein123): Flip this to true and/or remove completely once verified by Envoy Mobile. 111 : // TODO(mattklein123): Also unit test this if this sticks and this becomes the default for Apple & 112 : // Android. 113 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_always_use_v6); 114 : // TODO(pradeepcrao) reset this to true after 2 releases (1.27) 115 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_include_histograms); 116 : // TODO(wbpcode) complete remove this feature is no one use it. 117 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_refresh_rtt_after_request); 118 : // TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag. 119 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all); 120 : // TODO(steveWang) flip this to true after this is verified in prod. 121 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_quiche_use_mem_slice_releasor_api); 122 : // TODO(suniltheta): Once the newly added http async technique is stabilized move it under 123 : // RUNTIME_GUARD so that this option becomes default enabled. Once this option proves effective 124 : // remove the feature flag and remove code path that relies on old technique to fetch credentials 125 : // via libcurl and remove the bazel steps to pull and test the curl dependency. 126 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials); 127 : // TODO(adisuissa): enable by default once this is tested in prod. 128 : FALSE_RUNTIME_GUARD(envoy_restart_features_use_eds_cache_for_ads); 129 : // TODO(#10646) change to true when UHV is sufficiently tested 130 : // For more information about Universal Header Validation, please see 131 : // https://github.com/envoyproxy/envoy/issues/10646 132 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_enable_universal_header_validator); 133 : // TODO(pksohn): enable after fixing https://github.com/envoyproxy/envoy/issues/29930 134 : FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_defer_logging_to_ack_listener); 135 : // TODO(#31276): flip this to true after some test time. 136 : FALSE_RUNTIME_GUARD(envoy_restart_features_use_fast_protobuf_hash); 137 : 138 : // Block of non-boolean flags. Use of int flags is deprecated. Do not add more. 139 : ABSL_FLAG(uint64_t, re2_max_program_size_error_level, 100, ""); // NOLINT 140 : ABSL_FLAG(uint64_t, re2_max_program_size_warn_level, // NOLINT 141 : std::numeric_limits<uint32_t>::max(), ""); // NOLINT 142 : 143 : namespace Envoy { 144 : namespace Runtime { 145 : namespace { 146 : 147 3402 : std::string swapPrefix(std::string name) { 148 3402 : return absl::StrReplaceAll(name, {{"envoy_", "envoy."}, {"features_", "features."}}); 149 3402 : } 150 : 151 : } // namespace 152 : 153 : // This is a singleton class to map Envoy style flag names to absl flags 154 : class RuntimeFeatures { 155 : public: 156 : RuntimeFeatures(); 157 : 158 : // Get the command line flag corresponding to the Envoy style feature name, or 159 : // nullptr if it is not a registered flag. 160 75916 : absl::CommandLineFlag* getFlag(absl::string_view feature) const { 161 75916 : auto it = all_features_.find(feature); 162 75916 : if (it == all_features_.end()) { 163 220 : return nullptr; 164 220 : } 165 75696 : return it->second; 166 75916 : } 167 : 168 : private: 169 : absl::flat_hash_map<std::string, absl::CommandLineFlag*> all_features_; 170 : }; 171 : 172 : using RuntimeFeaturesDefaults = ConstSingleton<RuntimeFeatures>; 173 : 174 42 : RuntimeFeatures::RuntimeFeatures() { 175 42 : absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> flags = absl::GetAllFlags(); 176 8107 : for (auto& it : flags) { 177 8107 : absl::string_view name = it.second->Name(); 178 8107 : if ((!absl::StartsWith(name, "envoy_reloadable_features_") && 179 8107 : !absl::StartsWith(name, "envoy_restart_features_")) || 180 8107 : !it.second->TryGet<bool>().has_value()) { 181 4705 : continue; 182 4705 : } 183 3402 : std::string envoy_name = swapPrefix(std::string(name)); 184 3402 : all_features_.emplace(envoy_name, it.second); 185 3402 : } 186 42 : } 187 : 188 126 : bool hasRuntimePrefix(absl::string_view feature) { 189 : // Track Envoy reloadable and restart features, excluding synthetic QUIC flags 190 : // which are not tracked in the list below. 191 126 : return (absl::StartsWith(feature, "envoy.reloadable_features.") && 192 126 : !absl::StartsWith(feature, "envoy.reloadable_features.FLAGS_envoy_quic")) || 193 126 : absl::StartsWith(feature, "envoy.restart_features."); 194 126 : } 195 : 196 918 : bool isRuntimeFeature(absl::string_view feature) { 197 918 : return RuntimeFeaturesDefaults::get().getFlag(feature) != nullptr; 198 918 : } 199 : 200 72726 : bool runtimeFeatureEnabled(absl::string_view feature) { 201 72726 : absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(feature); 202 72726 : if (flag == nullptr) { 203 0 : IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", feature)); 204 0 : return false; 205 0 : } 206 : // We validate in map creation that the flag is a boolean. 207 72726 : return flag->TryGet<bool>().value(); 208 72726 : } 209 : 210 0 : uint64_t getInteger(absl::string_view feature, uint64_t default_value) { 211 : // DO NOT ADD MORE FLAGS HERE. This function deprecated. 212 0 : if (absl::StartsWith(feature, "re2.")) { 213 0 : if (feature == "re2.max_program_size.error_level") { 214 0 : return absl::GetFlag(FLAGS_re2_max_program_size_error_level); 215 0 : } else if (feature == "re2.max_program_size.warn_level") { 216 0 : return absl::GetFlag(FLAGS_re2_max_program_size_warn_level); 217 0 : } 218 0 : } 219 0 : IS_ENVOY_BUG(absl::StrCat("requested an unsupported integer ", feature)); 220 0 : return default_value; 221 0 : } 222 : 223 1701 : void markRuntimeInitialized() { 224 1701 : maybeSetRuntimeGuard("envoy.reloadable_features.runtime_initialized", true); 225 1701 : } 226 : 227 237 : bool isRuntimeInitialized() { 228 237 : return runtimeFeatureEnabled("envoy.reloadable_features.runtime_initialized"); 229 237 : } 230 : 231 2273 : void maybeSetRuntimeGuard(absl::string_view name, bool value) { 232 2273 : absl::CommandLineFlag* flag = RuntimeFeaturesDefaults::get().getFlag(name); 233 2273 : if (flag == nullptr) { 234 0 : IS_ENVOY_BUG(absl::StrCat("Unable to find runtime feature ", name)); 235 0 : return; 236 0 : } 237 2273 : std::string err; 238 2273 : flag->ParseFrom(value ? "true" : "false", &err); 239 2273 : } 240 : 241 0 : void maybeSetDeprecatedInts(absl::string_view name, uint32_t value) { 242 0 : if (!absl::StartsWith(name, "envoy.") && !absl::StartsWith(name, "re2.")) { 243 0 : return; 244 0 : } 245 : 246 : // DO NOT ADD MORE FLAGS HERE. This function deprecated. 247 0 : else if (name == "re2.max_program_size.error_level") { 248 0 : absl::SetFlag(&FLAGS_re2_max_program_size_error_level, value); 249 0 : } else if (name == "re2.max_program_size.warn_level") { 250 0 : absl::SetFlag(&FLAGS_re2_max_program_size_warn_level, value); 251 0 : } 252 0 : } 253 : 254 : } // namespace Runtime 255 : } // namespace Envoy