1
#include "source/common/router/route_config_update_receiver_impl.h"
2

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

            
6
#include "envoy/config/route/v3/route.pb.h"
7
#include "envoy/service/discovery/v3/discovery.pb.h"
8

            
9
#include "source/common/common/assert.h"
10
#include "source/common/common/fmt.h"
11
#include "source/common/common/thread.h"
12
#include "source/common/config/resource_name.h"
13
#include "source/common/protobuf/utility.h"
14
#include "source/common/router/config_impl.h"
15

            
16
namespace Envoy {
17
namespace Router {
18

            
19
namespace {
20

            
21
// Resets 'route_config::virtual_hosts' by merging VirtualHost contained in
22
// 'rds_vhosts' and 'vhds_vhosts'.
23
void rebuildRouteConfigVirtualHosts(
24
    const RouteConfigUpdateReceiverImpl::VirtualHostMap& rds_vhosts,
25
    const RouteConfigUpdateReceiverImpl::VirtualHostMap& vhds_vhosts,
26
79
    envoy::config::route::v3::RouteConfiguration& route_config) {
27
79
  route_config.clear_virtual_hosts();
28
79
  for (const auto& vhost : rds_vhosts) {
29
39
    route_config.mutable_virtual_hosts()->Add()->CheckTypeAndMergeFrom(vhost.second);
30
39
  }
31
117
  for (const auto& vhost : vhds_vhosts) {
32
117
    route_config.mutable_virtual_hosts()->Add()->CheckTypeAndMergeFrom(vhost.second);
33
117
  }
34
79
}
35

            
36
} // namespace
37

            
38
377
Rds::ConfigConstSharedPtr ConfigTraitsImpl::createNullConfig() const {
39
377
  return std::make_shared<NullConfigImpl>();
40
377
}
41

            
42
Rds::ConfigConstSharedPtr
43
ConfigTraitsImpl::createConfig(const Protobuf::Message& rc,
44
                               Server::Configuration::ServerFactoryContext& factory_context,
45
9908
                               bool validate_clusters_default) const {
46
9908
  ASSERT(dynamic_cast<const envoy::config::route::v3::RouteConfiguration*>(&rc));
47
9908
  return THROW_OR_RETURN_VALUE(
48
9908
      ConfigImpl::create(static_cast<const envoy::config::route::v3::RouteConfiguration&>(rc),
49
9908
                         factory_context, validator_, validate_clusters_default),
50
9908
      std::shared_ptr<ConfigImpl>);
51
9908
}
52

            
53
bool RouteConfigUpdateReceiverImpl::onRdsUpdate(const Protobuf::Message& rc,
54
443
                                                const std::string& version_info) {
55
443
  uint64_t new_hash = base_.getHash(rc);
56
443
  if (!base_.checkHash(new_hash)) {
57
52
    return false;
58
52
  }
59
391
  auto new_route_config = std::make_unique<envoy::config::route::v3::RouteConfiguration>();
60
391
  new_route_config->CheckTypeAndMergeFrom(rc);
61
391
  const uint64_t new_vhds_config_hash =
62
391
      new_route_config->has_vhds() ? MessageUtil::hash(new_route_config->vhds()) : 0ul;
63
391
  if (new_route_config->has_vhds()) {
64
    // When using VHDS, stash away RDS vhosts, so that they can be merged with VHDS vhosts in
65
    // onVhdsUpdate.
66
50
    if (rds_virtual_hosts_ == nullptr) {
67
47
      rds_virtual_hosts_ = std::make_unique<VirtualHostMap>();
68
47
    } else {
69
3
      rds_virtual_hosts_->clear();
70
3
    }
71
50
    for (const auto& vhost : new_route_config->virtual_hosts()) {
72
22
      rds_virtual_hosts_->emplace(vhost.name(), vhost);
73
22
    }
74
50
    if (vhds_virtual_hosts_ != nullptr && !vhds_virtual_hosts_->empty()) {
75
      // If there are vhosts supplied by VHDS, merge them with RDS vhosts.
76
3
      rebuildRouteConfigVirtualHosts(*rds_virtual_hosts_, *vhds_virtual_hosts_, *new_route_config);
77
3
    }
78
50
  }
79
391
  base_.updateConfig(std::move(new_route_config));
80
391
  base_.updateHash(new_hash);
81
391
  vhds_configuration_changed_ = new_vhds_config_hash != last_vhds_config_hash_;
82
391
  last_vhds_config_hash_ = new_vhds_config_hash;
83

            
84
391
  base_.onUpdateCommon(version_info);
85
391
  return true;
86
443
}
87

            
88
bool RouteConfigUpdateReceiverImpl::onVhdsUpdate(
89
    const VirtualHostRefVector& added_vhosts, std::set<std::string>&& added_resource_ids,
90
    const Protobuf::RepeatedPtrField<std::string>& removed_resources,
91
76
    const std::string& version_info) {
92
76
  std::unique_ptr<VirtualHostMap> vhosts_after_this_update;
93
76
  if (vhds_virtual_hosts_ != nullptr) {
94
36
    vhosts_after_this_update = std::make_unique<VirtualHostMap>(*vhds_virtual_hosts_);
95
48
  } else {
96
40
    vhosts_after_this_update = std::make_unique<VirtualHostMap>();
97
40
  }
98
76
  if (rds_virtual_hosts_ == nullptr) {
99
    rds_virtual_hosts_ = std::make_unique<VirtualHostMap>();
100
  }
101
76
  const bool removed = removeVhosts(*vhosts_after_this_update, removed_resources);
102
76
  const bool updated = updateVhosts(*vhosts_after_this_update, added_vhosts);
103

            
104
76
  auto route_config_after_this_update =
105
76
      std::make_unique<envoy::config::route::v3::RouteConfiguration>();
106
76
  route_config_after_this_update->CheckTypeAndMergeFrom(base_.protobufConfiguration());
107
76
  rebuildRouteConfigVirtualHosts(*rds_virtual_hosts_, *vhosts_after_this_update,
108
76
                                 *route_config_after_this_update);
109

            
110
76
  base_.updateConfig(std::move(route_config_after_this_update));
111
  // No exception, route_config_after_this_update is valid, can update the state.
112
76
  vhds_virtual_hosts_ = std::move(vhosts_after_this_update);
113
76
  resource_ids_in_last_update_ = std::move(added_resource_ids);
114
76
  base_.onUpdateCommon(version_info);
115

            
116
76
  return removed || updated || !resource_ids_in_last_update_.empty();
117
76
}
118

            
119
bool RouteConfigUpdateReceiverImpl::removeVhosts(
120
76
    VirtualHostMap& vhosts, const Protobuf::RepeatedPtrField<std::string>& removed_vhost_names) {
121
76
  bool vhosts_removed = false;
122
76
  for (const auto& vhost_name : removed_vhost_names) {
123
10
    auto found = vhosts.find(vhost_name);
124
10
    if (found != vhosts.end()) {
125
10
      vhosts_removed = true;
126
10
      vhosts.erase(vhost_name);
127
10
    }
128
10
  }
129
76
  return vhosts_removed;
130
76
}
131

            
132
bool RouteConfigUpdateReceiverImpl::updateVhosts(VirtualHostMap& vhosts,
133
76
                                                 const VirtualHostRefVector& added_vhosts) {
134
76
  bool vhosts_added = false;
135
78
  for (const auto& vhost : added_vhosts) {
136
78
    auto found = vhosts.find(vhost.get().name());
137
78
    if (found != vhosts.end()) {
138
6
      vhosts.erase(found);
139
6
    }
140
78
    vhosts.emplace(vhost.get().name(), vhost.get());
141
78
    vhosts_added = true;
142
78
  }
143
76
  return vhosts_added;
144
76
}
145

            
146
} // namespace Router
147
} // namespace Envoy