Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : // global_vrouter.cc - operational data for global vrouter configuration
6 :
7 : #include <mutex>
8 :
9 : #include <boost/foreach.hpp>
10 : #include <base/util.h>
11 : #include <cmn/agent_cmn.h>
12 : #include <cfg/cfg_init.h>
13 : #include <route/route.h>
14 :
15 : #include <vnc_cfg_types.h>
16 : #include <agent_types.h>
17 : #include <ifmap/ifmap_link.h>
18 : #include <ifmap/ifmap_node.h>
19 :
20 : #include <oper/operdb_init.h>
21 : #include <oper/peer.h>
22 : #include <oper/vrf.h>
23 : #include <oper/interface_common.h>
24 : #include <oper/nexthop.h>
25 : #include <oper/vn.h>
26 : #include <oper/mirror_table.h>
27 : #include <oper/vxlan.h>
28 : #include <oper/mpls.h>
29 : #include <oper/route_common.h>
30 : #include <oper/ecmp_load_balance.h>
31 : #include <oper/config_manager.h>
32 : #include <oper/crypt_tunnel.h>
33 :
34 : #include <oper/agent_route_walker.h>
35 : #include <oper/agent_route_resync.h>
36 : #include <oper/global_vrouter.h>
37 : #include <vrouter/flow_stats/flow_stats_collector.h>
38 :
39 : const std::string GlobalVrouter::kMetadataService = "metadata";
40 : const std::string GlobalVrouter::kMetadataService6 = "metadata6";
41 : const Ip4Address GlobalVrouter::kLoopBackIp = Ip4Address(0x7f000001);
42 :
43 0 : static int ProtocolToString(const std::string proto) {
44 0 : if (proto == "TCP" || proto == "tcp") {
45 0 : return IPPROTO_TCP;
46 : }
47 :
48 0 : if (proto == "UDP" || proto == "udp") {
49 0 : return IPPROTO_UDP;
50 : }
51 :
52 0 : if (proto == "ICMP" || proto == "icmp") {
53 0 : return IPPROTO_ICMP;
54 : }
55 :
56 0 : if (proto == "SCTP" || proto == "sctp") {
57 0 : return IPPROTO_SCTP;
58 : }
59 :
60 0 : if (proto == "all") {
61 0 : return 0;
62 : }
63 :
64 0 : return atoi(proto.c_str());
65 : }
66 :
67 1 : void GlobalVrouter::UpdateFlowAging(autogen::GlobalVrouterConfig *cfg) {
68 1 : if (agent()->flow_stats_req_handler() == NULL) {
69 0 : return;
70 : }
71 :
72 : std::vector<autogen::FlowAgingTimeout>::const_iterator new_list_it =
73 1 : cfg->flow_aging_timeout_list().begin();
74 1 : FlowAgingTimeoutMap new_flow_aging_timeout_map;
75 :
76 1 : while (new_list_it != cfg->flow_aging_timeout_list().end()) {
77 0 : int proto = ProtocolToString(new_list_it->protocol);
78 0 : if (proto < 0 || proto > 0xFF) {
79 0 : new_list_it++;
80 0 : continue;
81 : }
82 0 : FlowAgingTimeoutKey key(proto, new_list_it->port);
83 0 : agent()->flow_stats_req_handler()(agent(), proto, new_list_it->port,
84 0 : new_list_it->timeout_in_seconds);
85 :
86 0 : flow_aging_timeout_map_.erase(key);
87 0 : new_flow_aging_timeout_map.insert(
88 0 : FlowAgingTimeoutPair(key, new_list_it->timeout_in_seconds));
89 0 : new_list_it++;
90 : }
91 :
92 : FlowAgingTimeoutMap::const_iterator old_list_it =
93 1 : flow_aging_timeout_map_.begin();
94 1 : while (old_list_it != flow_aging_timeout_map_.end()) {
95 0 : agent()->flow_stats_req_handler()(agent(), old_list_it->first.protocol,
96 0 : old_list_it->first.port, 0);
97 0 : old_list_it++;
98 : }
99 1 : flow_aging_timeout_map_ = new_flow_aging_timeout_map;
100 1 : }
101 :
102 1 : void GlobalVrouter::DeleteFlowAging() {
103 :
104 1 : if (agent()->flow_stats_req_handler() == NULL) {
105 0 : return;
106 : }
107 :
108 : FlowAgingTimeoutMap::const_iterator old_list_it =
109 1 : flow_aging_timeout_map_.begin();
110 1 : while (old_list_it != flow_aging_timeout_map_.end()) {
111 0 : agent()->flow_stats_req_handler()(agent(), old_list_it->first.protocol,
112 0 : old_list_it->first.port, 0);
113 0 : old_list_it++;
114 : }
115 1 : flow_aging_timeout_map_.clear();
116 : }
117 :
118 1 : void GlobalVrouter::UpdatePortConfig(autogen::GlobalVrouterConfig *cfg) {
119 1 : if (agent()->port_config_handler() == NULL) {
120 0 : return;
121 : }
122 :
123 1 : ProtocolPortSet new_protocol_port_set;
124 : std::vector<autogen::PortTranslationPool>::const_iterator new_list_it =
125 1 : cfg->port_translation_pools().begin();
126 1 : for (;new_list_it != cfg->port_translation_pools().end(); new_list_it++) {
127 0 : int proto = ProtocolToString(new_list_it->protocol);
128 0 : if (proto < 0 || proto > 0xFF) {
129 0 : new_list_it++;
130 0 : continue;
131 : }
132 :
133 0 : if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
134 0 : continue;
135 : }
136 :
137 0 : uint16_t port_count = 0;
138 0 : std::stringstream str(new_list_it->port_count);
139 0 : str >> port_count;
140 :
141 0 : protocol_port_set_.erase(proto);
142 0 : if (new_list_it->port_range.start_port != 0 &&
143 0 : new_list_it->port_range.end_port != 0) {
144 0 : PortConfig::PortRange range(new_list_it->port_range.start_port,
145 0 : new_list_it->port_range.end_port);
146 0 : new_protocol_port_set[proto].port_range.push_back(range);
147 0 : } else if (port_count != 0) {
148 0 : new_protocol_port_set[proto].port_count = port_count;
149 : }
150 0 : }
151 :
152 : struct rlimit rl;
153 1 : int result = getrlimit(RLIMIT_NOFILE, &rl);
154 1 : int avail_count = 0;
155 1 : if (result == 0) {
156 1 : avail_count = rl.rlim_max - Agent::kMaxOtherOpenFds;
157 1 : if (avail_count < 0) {
158 0 : avail_count = 0;
159 : }
160 : }
161 :
162 :
163 1 : ProtocolPortSet::const_iterator old_list_it = protocol_port_set_.begin();
164 1 : for (; old_list_it != protocol_port_set_.end(); old_list_it++) {
165 0 : PortConfig pc;
166 0 : agent()->port_config_handler()(agent(), old_list_it->first, &pc);
167 0 : }
168 :
169 1 : int total_port_count = 0;
170 1 : ProtocolPortSet::iterator pc_list_it = new_protocol_port_set.begin();
171 1 : for (; pc_list_it != new_protocol_port_set.end(); pc_list_it++) {
172 0 : pc_list_it->second.Trim();
173 0 : total_port_count += pc_list_it->second.port_count;
174 : }
175 :
176 1 : float avail_percent = 1;
177 1 : if (total_port_count > avail_count) {
178 0 : avail_percent = (float)avail_count / (float)total_port_count;
179 : }
180 :
181 1 : pc_list_it = new_protocol_port_set.begin();
182 1 : for (; pc_list_it != new_protocol_port_set.end(); pc_list_it++) {
183 0 : pc_list_it->second.port_count *= avail_percent;
184 0 : agent()->port_config_handler()(agent(), pc_list_it->first,
185 0 : &(pc_list_it->second));
186 : }
187 :
188 1 : protocol_port_set_ = new_protocol_port_set;
189 1 : }
190 :
191 1 : void GlobalVrouter::DeletePortConfig() {
192 1 : ProtocolPortSet::const_iterator it = protocol_port_set_.begin();
193 1 : for (; it != protocol_port_set_.end(); it++) {
194 0 : PortConfig pc;
195 0 : agent()->port_config_handler()(agent(), it->first, &pc);
196 0 : }
197 :
198 1 : protocol_port_set_.clear();
199 1 : }
200 :
201 1 : void GlobalVrouter::ReadFlowsLimits(const autogen::GlobalVrouterConfig &cfg) {
202 : uint32_t max_vm_flows_percent;
203 : uint32_t global_max_vmi_flows;
204 1 : if (cfg.IsPropertySet(autogen::GlobalVrouterConfig::MAX_VM_FLOWS_PERCENT)) {
205 0 : max_vm_flows_percent = cfg.max_vm_flows_percent();
206 : } else {
207 1 : max_vm_flows_percent = FLOWS_LIMIT_UNLIMITED;
208 : }
209 1 : if (cfg.IsPropertySet(autogen::GlobalVrouterConfig::GLOBAL_MAX_VMI_FLOWS)) {
210 0 : global_max_vmi_flows = cfg.global_max_vmi_flows();
211 : } else {
212 1 : global_max_vmi_flows = FLOWS_LIMIT_UNLIMITED;
213 : }
214 1 : Agent *agent = this->agent();
215 1 : agent->set_max_vm_flows_perc(max_vm_flows_percent);
216 1 : agent->set_global_max_vmi_flows(global_max_vmi_flows);
217 1 : agent->update_max_vm_flows(agent->flow_table_size());
218 1 : }
219 :
220 : ////////////////////////////////////////////////////////////////////////////////
221 :
222 : // Link local service
223 0 : GlobalVrouter::LinkLocalService::LinkLocalService(
224 : const std::string &service_name,
225 : const std::string &fabric_dns_name,
226 : const std::vector<Ip4Address> &fabric_ip,
227 0 : uint16_t fabric_port)
228 0 : : linklocal_service_name(service_name),
229 0 : ipfabric_dns_service_name(fabric_dns_name),
230 0 : ipfabric_service_ip(fabric_ip),
231 0 : ipfabric_service_port(fabric_port) {
232 0 : }
233 :
234 0 : bool GlobalVrouter::LinkLocalService::operator==(
235 : const LinkLocalService &rhs) const {
236 0 : if (linklocal_service_name == rhs.linklocal_service_name &&
237 0 : ipfabric_dns_service_name == rhs.ipfabric_dns_service_name &&
238 0 : ipfabric_service_ip == rhs.ipfabric_service_ip &&
239 0 : ipfabric_service_port == rhs.ipfabric_service_port)
240 0 : return true;
241 0 : return false;
242 : }
243 :
244 0 : bool GlobalVrouter::LinkLocalService::IsAddressInUse(const Ip4Address &ip) const {
245 0 : BOOST_FOREACH(Ip4Address ipfabric_addr, ipfabric_service_ip) {
246 0 : if (ipfabric_addr == ip)
247 0 : return true;
248 : }
249 0 : return false;
250 : }
251 :
252 0 : bool GlobalVrouter::LinkLocalServiceKey::operator<(
253 : const LinkLocalServiceKey &rhs) const {
254 0 : if (linklocal_service_ip != rhs.linklocal_service_ip)
255 0 : return linklocal_service_ip < rhs.linklocal_service_ip;
256 0 : return linklocal_service_port < rhs.linklocal_service_port;
257 : }
258 :
259 : ////////////////////////////////////////////////////////////////////////////////
260 :
261 : // Async resolve DNS names (used to resolve names given in linklocal config)
262 : class GlobalVrouter::FabricDnsResolver {
263 : public:
264 : typedef boost::asio::ip::udp boost_udp;
265 : static const uint32_t kDnsTimeout = 15 * 60 * 1000; // fifteen minutes
266 :
267 1 : FabricDnsResolver(GlobalVrouter *vrouter, boost::asio::io_service &io)
268 2 : : request_count_(0), response_count_(0), global_vrouter_(vrouter),
269 1 : io_(io) {
270 : // start timer to re-resolve the DNS names to IP addresses
271 1 : timer_ = TimerManager::CreateTimer(io_, "DnsHandlerTimer");
272 1 : timer_->Start(kDnsTimeout,
273 : boost::bind(&GlobalVrouter::FabricDnsResolver::OnTimeout, this));
274 1 : }
275 2 : virtual ~FabricDnsResolver() {
276 1 : timer_->Cancel();
277 1 : TimerManager::DeleteTimer(timer_);
278 2 : }
279 :
280 : // Called in DB context, gives the list of names to be resolved
281 2 : void ResolveList(const std::vector<std::string> &name_list) {
282 2 : std::vector<Ip4Address> empty_addr_list;
283 2 : ResolveMap new_addr_map;
284 2 : std::scoped_lock lock(mutex_);
285 2 : BOOST_FOREACH(std::string name, name_list) {
286 0 : ResolveName(name);
287 0 : ResolveMap::iterator it = address_map_.find(name);
288 0 : if (it != address_map_.end()) {
289 0 : new_addr_map.insert(ResolvePair(name, it->second));
290 0 : address_map_.erase(it);
291 : } else {
292 0 : new_addr_map.insert(ResolvePair(name, empty_addr_list));
293 : }
294 0 : }
295 2 : address_map_.swap(new_addr_map);
296 2 : }
297 :
298 : // Called from client tasks to resolve name to address
299 0 : bool Resolve(const std::string &name, Ip4Address *address) {
300 0 : std::scoped_lock lock(mutex_);
301 0 : ResolveMap::iterator it = address_map_.find(name);
302 0 : if (it != address_map_.end() && it->second.size()) {
303 0 : int index = rand() % it->second.size();
304 0 : *address = it->second[index];
305 0 : if (*address == kLoopBackIp) {
306 0 : *address = global_vrouter_->agent()->router_id();
307 : }
308 0 : return true;
309 : }
310 0 : return false;
311 0 : }
312 :
313 : // Timer handler; re-resolve all DNS names
314 0 : bool OnTimeout() {
315 0 : std::scoped_lock lock(mutex_);
316 0 : for (ResolveMap::const_iterator it = address_map_.begin();
317 0 : it != address_map_.end(); ++it) {
318 0 : ResolveName(it->first);
319 : }
320 0 : return true;
321 0 : }
322 :
323 : // Called in DB context
324 0 : bool IsAddressInUse(const Ip4Address &ip) {
325 0 : std::scoped_lock lock(mutex_);
326 0 : for (ResolveMap::const_iterator it = address_map_.begin();
327 0 : it != address_map_.end(); ++it) {
328 0 : BOOST_FOREACH(Ip4Address address, it->second) {
329 0 : if (address == ip)
330 0 : return true;
331 : }
332 : }
333 0 : return false;
334 0 : }
335 :
336 0 : uint64_t PendingRequests() const {
337 0 : return request_count_ - response_count_;
338 : }
339 :
340 : private:
341 : typedef std::map<std::string, std::vector<Ip4Address> > ResolveMap;
342 : typedef std::pair<std::string, std::vector<Ip4Address> > ResolvePair;
343 :
344 0 : void ResolveName(const std::string &name) {
345 0 : boost_udp::resolver *resolver = new boost_udp::resolver(io_);
346 :
347 0 : resolver->async_resolve(
348 0 : boost_udp::resolver::query(boost_udp::v4(), name, "domain"),
349 0 : boost::bind(&GlobalVrouter::FabricDnsResolver::ResolveHandler, this,
350 : _1, _2, name, resolver));
351 0 : request_count_++;
352 0 : }
353 :
354 : // called in asio context, handle resolve response
355 0 : void ResolveHandler(const boost::system::error_code& error,
356 : boost_udp::resolver::iterator resolve_it,
357 : std::string &name, boost_udp::resolver *resolver) {
358 0 : std::vector<Ip4Address> old_list;
359 0 : ResolveMap::iterator addr_it;
360 0 : std::scoped_lock lock(mutex_);
361 0 : addr_it = address_map_.find(name);
362 0 : if (addr_it != address_map_.end()) {
363 0 : old_list.swap(addr_it->second);
364 0 : if (!error) {
365 0 : boost_udp::resolver::iterator end;
366 0 : while (resolve_it != end) {
367 0 : boost_udp::endpoint ep = *resolve_it;
368 0 : addr_it->second.push_back(ep.address().to_v4());
369 0 : resolve_it++;
370 : }
371 0 : }
372 0 : global_vrouter_->LinkLocalRouteUpdate(addr_it->second);
373 : }
374 0 : response_count_++;
375 0 : delete resolver;
376 0 : }
377 :
378 : Timer *timer_;
379 : std::mutex mutex_;
380 : ResolveMap address_map_;
381 : uint64_t request_count_;
382 : uint64_t response_count_;
383 : GlobalVrouter *global_vrouter_;
384 : boost::asio::io_service &io_;
385 : };
386 :
387 : ////////////////////////////////////////////////////////////////////////////////
388 :
389 : // Add / delete routes to ip fabric servers used for link local services
390 : // Also, add / delete receive routes for link local addresses in different VRFs
391 : class GlobalVrouter::LinkLocalRouteManager {
392 : public:
393 1 : LinkLocalRouteManager(GlobalVrouter *vrouter)
394 1 : : global_vrouter_(vrouter), vn_id_(DBTableBase::kInvalidId){
395 1 : }
396 :
397 2 : virtual ~LinkLocalRouteManager() {
398 1 : DeleteDBClients();
399 1 : ipfabric_address_list_.clear();
400 1 : linklocal_address_list_.clear();
401 2 : }
402 :
403 : void CreateDBClients();
404 : void DeleteDBClients();
405 : void AddArpRoute(const Ip4Address &srv);
406 : void UpdateAllVns(const LinkLocalServiceKey &key, bool is_add);
407 :
408 : private:
409 : bool VnUpdateWalk(DBEntryBase *entry, const LinkLocalServiceKey key,
410 : bool is_add);
411 : void VnWalkDone(DBTable::DBTableWalkRef ref);
412 : bool VnNotify(DBTablePartBase *partition, DBEntryBase *entry);
413 :
414 : GlobalVrouter *global_vrouter_;
415 : DBTableBase::ListenerId vn_id_;
416 : std::set<Ip4Address> ipfabric_address_list_;
417 : std::set<IpAddress> linklocal_address_list_;
418 : };
419 :
420 1 : void GlobalVrouter::LinkLocalRouteManager::CreateDBClients() {
421 1 : vn_id_ = global_vrouter_->agent()->vn_table()->Register(
422 : boost::bind(&GlobalVrouter::LinkLocalRouteManager::VnNotify,
423 : this, _1, _2));
424 1 : }
425 :
426 1 : void GlobalVrouter::LinkLocalRouteManager::DeleteDBClients() {
427 1 : global_vrouter_->agent()->vn_table()->Unregister(vn_id_);
428 1 : }
429 :
430 0 : void GlobalVrouter::LinkLocalRouteManager::AddArpRoute(const Ip4Address &srv) {
431 0 : std::set<Ip4Address>::iterator it;
432 0 : std::pair<std::set<Ip4Address>::iterator, bool> ret;
433 :
434 0 : ret = ipfabric_address_list_.insert(srv);
435 0 : if (ret.second == false) {
436 0 : return;
437 : }
438 :
439 0 : Agent *agent = global_vrouter_->agent();
440 0 : VnListType vn_list;
441 0 : vn_list.insert(agent->fabric_vn_name());
442 0 : InetUnicastAgentRouteTable::CheckAndAddArpReq(agent->fabric_vrf_name(),
443 : srv, agent->vhost_interface(),
444 0 : vn_list, SecurityGroupList(),
445 0 : TagList());
446 0 : }
447 :
448 : // Walk thru all the VNs
449 0 : void GlobalVrouter::LinkLocalRouteManager::UpdateAllVns(
450 : const LinkLocalServiceKey &key, bool is_add) {
451 0 : if (is_add) {
452 0 : if (!linklocal_address_list_.insert(key.linklocal_service_ip).second)
453 0 : return;
454 : } else {
455 0 : if (!linklocal_address_list_.erase(key.linklocal_service_ip))
456 0 : return;
457 : }
458 : // This walker allocation has to be done everytime as function argument
459 : // takes key and is_add which keeps varying. So boost bind needs to be
460 : // redone.
461 : // Also thats the reason why previous walk is also not stopped and it runs
462 : // to completion.
463 : // TODO: Evaluate if this can be optimized
464 : DBTable::DBTableWalkRef walk_ref =
465 0 : global_vrouter_->agent()->vn_table()->AllocWalker(
466 0 : boost::bind(&GlobalVrouter::LinkLocalRouteManager::VnUpdateWalk,
467 : this, _2, key, is_add),
468 : boost::bind(&GlobalVrouter::LinkLocalRouteManager::VnWalkDone,
469 0 : this, _1));
470 0 : global_vrouter_->agent()->vn_table()->WalkAgain(walk_ref);
471 0 : }
472 :
473 : // Vn Walk method
474 : // For each Vn, add or delete receive route for the specified linklocal service
475 0 : bool GlobalVrouter::LinkLocalRouteManager::VnUpdateWalk(
476 : DBEntryBase *entry, const LinkLocalServiceKey key, bool is_add) {
477 :
478 0 : VnEntry *vn_entry = static_cast<VnEntry *>(entry);
479 0 : if (vn_entry->IsDeleted()) {
480 0 : return true;
481 : }
482 :
483 0 : VrfEntry *vrf_entry = vn_entry->GetVrf();
484 0 : if (!vrf_entry) {
485 0 : return true;
486 : }
487 :
488 0 : Agent *agent = global_vrouter_->agent();
489 : // Do not create the routes for the default VRF
490 0 : if (agent->fabric_vrf_name() == vrf_entry->GetName()) {
491 0 : return true;
492 : }
493 :
494 : InetUnicastAgentRouteTable *rt_table =
495 0 : vrf_entry->GetInetUnicastRouteTable(key.linklocal_service_ip);
496 :
497 : LinkLocalDBState *state = static_cast<LinkLocalDBState *>
498 0 : (vn_entry->GetState(vn_entry->get_table_partition()->parent(), vn_id_));
499 0 : if (!state) {
500 0 : return true;
501 : }
502 :
503 0 : if (is_add) {
504 0 : if (vn_entry->layer3_forwarding()) {
505 0 : state->Add(key.linklocal_service_ip);
506 : VmInterfaceKey vmi_key(AgentKey::ADD_DEL_CHANGE,
507 0 : boost::uuids::nil_uuid(),
508 0 : agent->vhost_interface_name());
509 :
510 0 : rt_table->AddVHostRecvRoute(agent->link_local_peer(),
511 : vrf_entry->GetName(),
512 : vmi_key,
513 0 : key.linklocal_service_ip,
514 0 : key.linklocal_service_ip.is_v4() ? 32 : 128,
515 : vn_entry->GetName(),
516 : true, false, false);
517 0 : }
518 : } else {
519 0 : state->Delete(key.linklocal_service_ip);
520 0 : rt_table->DeleteReq(agent->link_local_peer(), vrf_entry->GetName(),
521 0 : key.linklocal_service_ip,
522 0 : key.linklocal_service_ip.is_v4() ? 32 : 128, NULL);
523 : }
524 0 : return true;
525 : }
526 :
527 : void
528 0 : GlobalVrouter::LinkLocalRouteManager::VnWalkDone(DBTable::DBTableWalkRef ref) {
529 0 : global_vrouter_->agent()->vn_table()->ReleaseWalker(ref);
530 0 : }
531 :
532 : // VN notify handler
533 19 : bool GlobalVrouter::LinkLocalRouteManager::VnNotify(DBTablePartBase *partition,
534 : DBEntryBase *entry) {
535 19 : VnEntry *vn_entry = static_cast<VnEntry *>(entry);
536 19 : VrfEntry *vrf_entry = vn_entry->GetVrf();
537 19 : Agent *agent = global_vrouter_->agent();
538 19 : if (vn_entry->IsDeleted() || !vn_entry->layer3_forwarding() || !vrf_entry) {
539 : LinkLocalDBState *state = static_cast<LinkLocalDBState *>
540 16 : (vn_entry->GetState(partition->parent(), vn_id_));
541 16 : if (!state)
542 13 : return true;
543 3 : for (std::set<IpAddress>::const_iterator it =
544 6 : state->addresses_.begin(); it != state->addresses_.end(); ++it) {
545 : InetUnicastAgentRouteTable *rt_table =
546 0 : state->vrf_->GetInetUnicastRouteTable(*it);
547 0 : rt_table->DeleteReq(agent->link_local_peer(),
548 0 : state->vrf_->GetName(), *it, it->is_v4() ? 32 : 128, NULL);
549 : }
550 3 : vn_entry->ClearState(partition->parent(), vn_id_);
551 3 : delete state;
552 3 : return true;
553 : }
554 :
555 : // Do not create the routes for the default VRF
556 3 : if (agent->fabric_vrf_name() == vrf_entry->GetName()) {
557 0 : return true;
558 : }
559 :
560 3 : if (vn_entry->layer3_forwarding()) {
561 3 : if (vn_entry->GetState(partition->parent(), vn_id_))
562 0 : return true;
563 3 : LinkLocalDBState *state = new LinkLocalDBState(vrf_entry);
564 3 : vn_entry->SetState(partition->parent(), vn_id_, state);
565 3 : InetUnicastAgentRouteTable *rt_table = NULL;
566 : const GlobalVrouter::LinkLocalServicesMap &services =
567 3 : global_vrouter_->linklocal_services_map();
568 3 : for (GlobalVrouter::LinkLocalServicesMap::const_iterator it =
569 6 : services.begin(); it != services.end(); ++it) {
570 : VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE,
571 0 : boost::uuids::nil_uuid(),
572 0 : agent->vhost_interface_name());
573 : rt_table =
574 0 : vrf_entry->GetInetUnicastRouteTable(it->first.linklocal_service_ip);
575 0 : state->Add(it->first.linklocal_service_ip);
576 0 : rt_table->AddVHostRecvRoute(agent->link_local_peer(),
577 : vrf_entry->GetName(),
578 : key,
579 0 : it->first.linklocal_service_ip,
580 0 : it->first.linklocal_service_ip.is_v4() ? 32 : 128,
581 : vn_entry->GetName(),
582 : true, false, false);
583 0 : }
584 : }
585 3 : return true;
586 : }
587 :
588 : ////////////////////////////////////////////////////////////////////////////////
589 :
590 1 : GlobalVrouter::GlobalVrouter(Agent *agent) :
591 1 : OperIFMapTable(agent), linklocal_services_map_(),
592 1 : crypt_tunnels_map_(), crypt_mode_(CRYPT_NONE),
593 1 : linklocal_route_mgr_(new LinkLocalRouteManager(this)),
594 1 : fabric_dns_resolver_(new FabricDnsResolver
595 1 : (this, *(agent->event_manager()->io_service()))),
596 1 : forwarding_mode_(Agent::L2_L3), flow_export_rate_(kDefaultFlowExportRate),
597 1 : ecmp_load_balance_(), configured_(false),
598 3 : slo_uuid_(boost::uuids::nil_uuid()) {
599 : agent_route_resync_walker_.reset
600 1 : (new AgentRouteResync("GlobalVrouterRouteWalker", agent));
601 : agent->oper_db()->agent_route_walk_manager()->
602 1 : RegisterWalker(static_cast<AgentRouteWalker *>
603 : (agent_route_resync_walker_.get()));
604 1 : }
605 :
606 2 : GlobalVrouter::~GlobalVrouter() {
607 : agent()->oper_db()->agent_route_walk_manager()->
608 1 : ReleaseWalker(agent_route_resync_walker_.get());
609 2 : }
610 :
611 :
612 0 : uint64_t GlobalVrouter::PendingFabricDnsRequests() const {
613 0 : return fabric_dns_resolver_.get()->PendingRequests();
614 : }
615 :
616 1 : void GlobalVrouter::CreateDBClients() {
617 1 : linklocal_route_mgr_->CreateDBClients();
618 1 : }
619 :
620 1 : void GlobalVrouter::ConfigDelete(IFMapNode *node) {
621 1 : GlobalVrouterConfig(node);
622 1 : configured_ = false;
623 1 : agent()->connection_state()->Update();
624 1 : return;
625 : }
626 :
627 1 : void GlobalVrouter::ConfigAddChange(IFMapNode *node) {
628 1 : GlobalVrouterConfig(node);
629 1 : configured_ = true;
630 1 : agent()->connection_state()->Update();
631 1 : return;
632 : }
633 :
634 1 : void GlobalVrouter::ConfigManagerEnqueue(IFMapNode *node) {
635 1 : agent()->config_manager()->AddGlobalVrouterNode(node);
636 1 : }
637 :
638 1 : void GlobalVrouter::UpdateSLOConfig(IFMapNode *node) {
639 1 : IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
640 1 : DBGraph *graph = table->GetGraph();
641 1 : for (DBGraphVertex::adjacency_iterator iter = node->begin(graph);
642 1 : iter != node->end(table->GetGraph()); ++iter) {
643 :
644 0 : IFMapNode *adj_node = static_cast<IFMapNode *>(iter.operator->());
645 0 : if (agent()->config_manager()->SkipNode(adj_node)) {
646 0 : continue;
647 : }
648 :
649 0 : if (adj_node->table() == agent()->cfg()->cfg_slo_table()) {
650 : autogen::SecurityLoggingObject *slo =
651 : static_cast<autogen::SecurityLoggingObject *>(adj_node->
652 0 : GetObject());
653 0 : autogen::IdPermsType id_perms = slo->id_perms();
654 0 : CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong,
655 0 : slo_uuid_);
656 0 : }
657 : }
658 1 : }
659 :
660 : // Handle incoming global vrouter configuration
661 2 : void GlobalVrouter::GlobalVrouterConfig(IFMapNode *node) {
662 2 : Agent::VxLanNetworkIdentifierMode cfg_vxlan_network_identifier_mode =
663 : Agent::AUTOMATIC;
664 2 : bool resync_vn = false; //resync_vn walks internally calls VMI walk.
665 2 : bool resync_route = false;
666 :
667 2 : if (node->IsDeleted() == false) {
668 1 : UpdateSLOConfig(node);
669 :
670 : autogen::GlobalVrouterConfig *cfg =
671 1 : static_cast<autogen::GlobalVrouterConfig *>(node->GetObject());
672 :
673 1 : agent()->set_global_slo_status(cfg->enable_security_logging());
674 :
675 : resync_route =
676 1 : TunnelType::EncapPrioritySync(cfg->encapsulation_priorities());
677 1 : if (cfg->vxlan_network_identifier_mode() == "configured") {
678 0 : cfg_vxlan_network_identifier_mode = Agent::CONFIGURED;
679 : }
680 1 : UpdateLinkLocalServiceConfig(cfg->linklocal_services());
681 1 : UpdateCryptTunnelEndpointConfig(cfg->encryption_tunnel_endpoints(),
682 1 : cfg->encryption_mode());
683 :
684 : //Take the forwarding mode if its set, else fallback to l2_l3.
685 : Agent::ForwardingMode new_forwarding_mode =
686 1 : agent()->TranslateForwardingMode(cfg->forwarding_mode());
687 1 : if (new_forwarding_mode != forwarding_mode_) {
688 1 : forwarding_mode_ = new_forwarding_mode;
689 1 : resync_route = true;
690 1 : resync_vn = true;
691 : }
692 1 : if (cfg->IsPropertySet
693 1 : (autogen::GlobalVrouterConfig::FLOW_EXPORT_RATE)) {
694 1 : flow_export_rate_ = cfg->flow_export_rate();
695 : } else {
696 0 : flow_export_rate_ = kDefaultFlowExportRate;
697 : }
698 1 : UpdateFlowAging(cfg);
699 1 : UpdatePortConfig(cfg);
700 1 : EcmpLoadBalance ecmp_load_balance;
701 1 : if (cfg->ecmp_hashing_include_fields().hashing_configured) {
702 0 : ecmp_load_balance.UpdateFields(cfg->
703 0 : ecmp_hashing_include_fields());
704 : }
705 1 : if (ecmp_load_balance_ != ecmp_load_balance) {
706 0 : ecmp_load_balance_ = ecmp_load_balance;
707 0 : resync_vn = true;
708 : }
709 1 : ReadFlowsLimits(*cfg);
710 1 : } else {
711 1 : DeleteLinkLocalServiceConfig();
712 1 : TunnelType::DeletePriorityList();
713 1 : resync_route = true;
714 1 : flow_export_rate_ = kDefaultFlowExportRate;
715 1 : DeleteFlowAging();
716 1 : DeletePortConfig();
717 : }
718 :
719 2 : if (cfg_vxlan_network_identifier_mode !=
720 2 : agent()->vxlan_network_identifier_mode()) {
721 : agent()->set_vxlan_network_identifier_mode
722 0 : (cfg_vxlan_network_identifier_mode);
723 0 : resync_vn = true;
724 : }
725 :
726 : //Rebakes
727 2 : if (resync_route) {
728 : //Resync vm_interfaces to handle ethernet tag change if vxlan changed to
729 : //mpls or vice versa.
730 : //Update all routes irrespectively as this will handle change of
731 : //priority between MPLS-UDP to MPLS-GRE and vice versa.
732 2 : ResyncRoutes();
733 2 : resync_vn = true;
734 : }
735 :
736 : //Rebakes VN and then all interfaces.
737 2 : if (resync_vn)
738 2 : agent()->vn_table()->GlobalVrouterConfigChanged();
739 2 : }
740 :
741 : // Get link local service configuration info, for a given service name
742 0 : bool GlobalVrouter::FindLinkLocalService(const std::string &service_name,
743 : IpAddress *service_ip,
744 : uint16_t *service_port,
745 : std::string *fabric_hostname,
746 : Ip4Address *fabric_ip,
747 : uint16_t *fabric_port) const {
748 0 : std::string name = boost::to_lower_copy(service_name);
749 :
750 0 : for (GlobalVrouter::LinkLocalServicesMap::const_iterator it =
751 0 : linklocal_services_map_.begin();
752 0 : it != linklocal_services_map_.end(); ++it) {
753 0 : if (it->second.linklocal_service_name == name) {
754 0 : *service_ip = it->first.linklocal_service_ip;
755 0 : *service_port = it->first.linklocal_service_port;
756 0 : *fabric_port = it->second.ipfabric_service_port;
757 0 : *fabric_hostname = it->second.ipfabric_dns_service_name;
758 0 : if (it->second.ipfabric_service_ip.size()) {
759 : // if there are multiple addresses, return one of them
760 0 : int index = rand() % it->second.ipfabric_service_ip.size();
761 0 : *fabric_ip = it->second.ipfabric_service_ip[index];
762 0 : if (*fabric_ip == kLoopBackIp) {
763 0 : *fabric_ip = agent()->router_id();
764 : }
765 0 : if (it->second.ipfabric_dns_service_name.empty())
766 0 : *fabric_hostname = fabric_ip->to_string();
767 0 : return true;
768 0 : } else if (!it->second.ipfabric_dns_service_name.empty()) {
769 0 : return fabric_dns_resolver_->Resolve(
770 0 : it->second.ipfabric_dns_service_name, fabric_ip);
771 : }
772 : }
773 : }
774 0 : return false;
775 0 : }
776 :
777 : // Get link local service info for a given linklocal service <ip, port>
778 18 : bool GlobalVrouter::FindLinkLocalService(const IpAddress &service_ip,
779 : uint16_t service_port,
780 : std::string *service_name,
781 : Ip4Address *fabric_ip,
782 : uint16_t *fabric_port) const {
783 : LinkLocalServicesMap::const_iterator it =
784 18 : linklocal_services_map_.find(LinkLocalServiceKey(service_ip,
785 : service_port));
786 18 : if (it == linklocal_services_map_.end()) {
787 : #if 0
788 : if (!service_port) {
789 : // to support ping to metadata address
790 : IpAddress metadata_service_ip;
791 : Ip4Address metadata_fabric_ip;
792 : uint16_t metadata_service_port, metadata_fabric_port;
793 : if (FindLinkLocalService(GlobalVrouter::kMetadataService,
794 : &metadata_service_ip,
795 : &metadata_service_port,
796 : &metadata_fabric_ip,
797 : &metadata_fabric_port) &&
798 : service_ip == metadata_service_ip) {
799 : *fabric_port = agent()->metadata_server_port();
800 : *fabric_ip = agent()->router_id();
801 : return true;
802 : }
803 : }
804 : #endif
805 18 : return false;
806 : }
807 :
808 0 : *service_name = it->second.linklocal_service_name;
809 0 : if (service_name->find(GlobalVrouter::kMetadataService)
810 0 : != std::string::npos) {
811 : // for metadata, return vhost0 ip and HTTP proxy port
812 0 : *fabric_port = agent()->metadata_server_port();
813 0 : *fabric_ip = agent()->router_id();
814 0 : return true;
815 : }
816 :
817 0 : *fabric_port = it->second.ipfabric_service_port;
818 : // if there are multiple addresses, return one of them
819 0 : if (it->second.ipfabric_service_ip.size()) {
820 0 : int index = rand() % it->second.ipfabric_service_ip.size();
821 0 : *fabric_ip = it->second.ipfabric_service_ip[index];
822 0 : if (*fabric_ip == kLoopBackIp) {
823 0 : *fabric_ip = agent()->router_id();
824 : }
825 0 : return true;
826 0 : } else if (!it->second.ipfabric_dns_service_name.empty()) {
827 0 : return fabric_dns_resolver_->Resolve(
828 0 : it->second.ipfabric_dns_service_name, fabric_ip);
829 : }
830 0 : return false;
831 : }
832 :
833 : // Get link local services, for a given service name
834 0 : bool GlobalVrouter::FindLinkLocalService(const std::string &service_name,
835 : std::set<IpAddress> *service_ip
836 : ) const {
837 0 : if (service_name.empty())
838 0 : return false;
839 :
840 0 : std::string name = boost::to_lower_copy(service_name);
841 0 : for (GlobalVrouter::LinkLocalServicesMap::const_iterator it =
842 0 : linklocal_services_map_.begin();
843 0 : it != linklocal_services_map_.end(); ++it) {
844 0 : if (it->second.linklocal_service_name == name) {
845 0 : service_ip->insert(it->first.linklocal_service_ip);
846 : }
847 : }
848 :
849 0 : return (service_ip->size() > 0);
850 0 : }
851 :
852 : // Get link local services info for a given linklocal service <ip>
853 0 : bool GlobalVrouter::FindLinkLocalService(const IpAddress &service_ip,
854 : std::set<std::string> *service_names
855 : ) const {
856 : LinkLocalServicesMap::const_iterator it =
857 0 : linklocal_services_map_.lower_bound(LinkLocalServiceKey(service_ip, 0));
858 :
859 0 : while (it != linklocal_services_map_.end() &&
860 0 : it->first.linklocal_service_ip == service_ip) {
861 0 : service_names->insert(it->second.linklocal_service_name);
862 0 : it++;
863 : }
864 :
865 0 : return (service_names->size() > 0);
866 : }
867 :
868 : // Handle changes to link local service configuration
869 1 : void GlobalVrouter::UpdateLinkLocalServiceConfig(
870 : const LinkLocalServiceList &linklocal_list) {
871 :
872 1 : std::vector<std::string> dns_name_list;
873 1 : LinkLocalServicesMap linklocal_services_map;
874 1 : for (std::vector<autogen::LinklocalServiceEntryType>::const_iterator it =
875 2 : linklocal_list.begin(); it != linklocal_list.end(); it++) {
876 0 : boost::system::error_code ec;
877 0 : IpAddress llip = IpAddress::from_string(it->linklocal_service_ip, ec);
878 0 : std::vector<Ip4Address> fabric_ip;
879 0 : BOOST_FOREACH(std::string ip_fabric_ip, it->ip_fabric_service_ip) {
880 0 : Ip4Address ip = Ip4Address::from_string(ip_fabric_ip, ec);
881 0 : if (ec) continue;
882 0 : fabric_ip.push_back(ip);
883 0 : }
884 0 : std::string name = boost::to_lower_copy(it->linklocal_service_name);
885 0 : linklocal_services_map.insert(LinkLocalServicesPair(
886 0 : LinkLocalServiceKey(llip, it->linklocal_service_port),
887 0 : LinkLocalService(name, it->ip_fabric_DNS_service_name,
888 0 : fabric_ip, it->ip_fabric_service_port)));
889 0 : if (!it->ip_fabric_DNS_service_name.empty())
890 0 : dns_name_list.push_back(it->ip_fabric_DNS_service_name);
891 0 : }
892 :
893 1 : linklocal_services_map_.swap(linklocal_services_map);
894 1 : fabric_dns_resolver_->ResolveList(dns_name_list);
895 1 : ChangeNotify(&linklocal_services_map, &linklocal_services_map_);
896 1 : }
897 :
898 1 : void GlobalVrouter::DeleteLinkLocalServiceConfig() {
899 1 : std::vector<std::string> dns_name_list;
900 1 : LinkLocalServicesMap linklocal_services_map;
901 :
902 1 : linklocal_services_map_.swap(linklocal_services_map);
903 1 : fabric_dns_resolver_->ResolveList(dns_name_list);
904 1 : ChangeNotify(&linklocal_services_map, &linklocal_services_map_);
905 1 : }
906 :
907 : // Identify linklocal service configuration changes from old to new
908 2 : bool GlobalVrouter::ChangeNotify(LinkLocalServicesMap *old_value,
909 : LinkLocalServicesMap *new_value) {
910 2 : bool change = false;
911 2 : LinkLocalServicesMap::iterator it_old = old_value->begin();
912 2 : LinkLocalServicesMap::iterator it_new = new_value->begin();
913 2 : while (it_old != old_value->end() && it_new != new_value->end()) {
914 0 : if (it_old->first < it_new->first) {
915 : // old entry is deleted
916 0 : DeleteLinkLocalService(it_old);
917 0 : change = true;
918 0 : it_old++;
919 0 : } else if (it_new->first < it_old->first) {
920 : // new entry
921 0 : AddLinkLocalService(it_new);
922 0 : change = true;
923 0 : it_new++;
924 0 : } else if (it_new->second == it_old->second) {
925 : // no change in entry
926 0 : it_old++;
927 0 : it_new++;
928 : } else {
929 : // change in entry
930 0 : ChangeLinkLocalService(it_old, it_new);
931 0 : change = true;
932 0 : it_old++;
933 0 : it_new++;
934 : }
935 : }
936 :
937 : // delete remaining old entries
938 2 : for (; it_old != old_value->end(); ++it_old) {
939 0 : DeleteLinkLocalService(it_old);
940 0 : change = true;
941 : }
942 :
943 : // add remaining new entries
944 2 : for (; it_new != new_value->end(); ++it_new) {
945 0 : AddLinkLocalService(it_new);
946 0 : change = true;
947 : }
948 :
949 2 : return change;
950 : }
951 :
952 : // New link local service
953 0 : void GlobalVrouter::AddLinkLocalService(
954 : const LinkLocalServicesMap::iterator &it) {
955 0 : linklocal_route_mgr_->UpdateAllVns(it->first, true);
956 0 : BOOST_FOREACH(Ip4Address ip, it->second.ipfabric_service_ip) {
957 0 : linklocal_route_mgr_->AddArpRoute(ip);
958 : }
959 0 : }
960 :
961 : // Link local service deleted
962 0 : void GlobalVrouter::DeleteLinkLocalService(
963 : const LinkLocalServicesMap::iterator &it) {
964 0 : if (!IsLinkLocalAddressInUse(it->first.linklocal_service_ip))
965 0 : linklocal_route_mgr_->UpdateAllVns(it->first, false);
966 0 : }
967 :
968 : // Change in Link local service
969 0 : void GlobalVrouter::ChangeLinkLocalService(
970 : const LinkLocalServicesMap::iterator &old_it,
971 : const LinkLocalServicesMap::iterator &new_it) {
972 0 : if (old_it->first.linklocal_service_ip !=
973 0 : new_it->first.linklocal_service_ip) {
974 0 : if (!IsLinkLocalAddressInUse(old_it->first.linklocal_service_ip))
975 0 : linklocal_route_mgr_->UpdateAllVns(old_it->first, false);
976 0 : linklocal_route_mgr_->UpdateAllVns(new_it->first, true);
977 : }
978 0 : LinkLocalRouteUpdate(new_it->second.ipfabric_service_ip);
979 0 : }
980 :
981 0 : void GlobalVrouter::LinkLocalRouteUpdate(
982 : const std::vector<Ip4Address> &addr_list) {
983 0 : BOOST_FOREACH(Ip4Address ip, addr_list) {
984 0 : linklocal_route_mgr_->AddArpRoute(ip);
985 : }
986 0 : }
987 :
988 0 : bool GlobalVrouter::IsAddressInUse(const Ip4Address &ip) const {
989 0 : for (LinkLocalServicesMap::const_iterator it =
990 0 : linklocal_services_map_.begin(); it != linklocal_services_map_.end();
991 0 : ++it) {
992 0 : if (it->second.IsAddressInUse(ip))
993 0 : return true;
994 : }
995 0 : return fabric_dns_resolver_->IsAddressInUse(ip);
996 : }
997 :
998 0 : bool GlobalVrouter::IsLinkLocalAddressInUse(const IpAddress &ip) const {
999 0 : for (LinkLocalServicesMap::const_iterator it =
1000 0 : linklocal_services_map_.begin(); it != linklocal_services_map_.end();
1001 0 : ++it) {
1002 0 : if (it->first.linklocal_service_ip == ip)
1003 0 : return true;
1004 : }
1005 0 : return false;
1006 : }
1007 :
1008 2 : void GlobalVrouter::ResyncRoutes() {
1009 2 : (static_cast<AgentRouteResync *>(agent_route_resync_walker_.get()))->
1010 2 : Update();
1011 2 : }
1012 :
1013 27 : const EcmpLoadBalance &GlobalVrouter::ecmp_load_balance() const {
1014 27 : return ecmp_load_balance_;
1015 : }
1016 :
1017 : ////////////////////////////////////////////////////////////////////////////////
1018 :
1019 0 : void LinkLocalServiceInfo::HandleRequest() const {
1020 0 : LinkLocalServiceResponse *resp = new LinkLocalServiceResponse();
1021 0 : std::vector<LinkLocalServiceData> linklocal_list;
1022 : const GlobalVrouter::LinkLocalServicesMap &services =
1023 : Agent::GetInstance()->oper_db()->
1024 0 : global_vrouter()->linklocal_services_map();
1025 :
1026 0 : for (GlobalVrouter::LinkLocalServicesMap::const_iterator it =
1027 0 : services.begin(); it != services.end(); ++it) {
1028 0 : LinkLocalServiceData service;
1029 0 : service.linklocal_service_name = it->second.linklocal_service_name;
1030 : service.linklocal_service_ip =
1031 0 : it->first.linklocal_service_ip.to_string();
1032 0 : service.linklocal_service_port = it->first.linklocal_service_port;
1033 0 : service.ipfabric_dns_name = it->second.ipfabric_dns_service_name;
1034 0 : BOOST_FOREACH(Ip4Address ip, it->second.ipfabric_service_ip) {
1035 0 : service.ipfabric_ip.push_back(ip.to_string());
1036 : }
1037 0 : service.ipfabric_port = it->second.ipfabric_service_port;
1038 0 : linklocal_list.push_back(service);
1039 0 : }
1040 :
1041 0 : resp->set_service_list(linklocal_list);
1042 0 : resp->set_context(context());
1043 0 : resp->Response();
1044 0 : }
1045 :
1046 : ////////////////////////////////////////////////////////////////////////////////
1047 :
1048 0 : bool GlobalVrouter::IsVrouterPresentCryptTunnelConfig(
1049 : const EncryptionTunnelEndpointList &endpoint_list) {
1050 0 : bool vrouter_present = false;
1051 0 : for (EncryptionTunnelEndpointList::const_iterator it = endpoint_list.begin();
1052 0 : it != endpoint_list.end(); it++) {
1053 0 : if (it->tunnel_remote_ip_address.compare(agent()->router_id().to_string()) == 0) {
1054 0 : vrouter_present = true;
1055 0 : break;
1056 : }
1057 : }
1058 0 : return vrouter_present;
1059 : }
1060 :
1061 : // Handle changes for cryptunnels
1062 1 : void GlobalVrouter::UpdateCryptTunnelEndpointConfig(
1063 : const EncryptionTunnelEndpointList &endpoint_list, const std::string encrypt_mode_str) {
1064 1 : CryptMode mode = GlobalVrouter::CRYPT_NONE;
1065 1 : CryptTunnelsMap crypt_tunnels_map;
1066 1 : if (!agent()->crypt_interface())
1067 1 : return;
1068 0 : if (IsVrouterPresentCryptTunnelConfig(endpoint_list)) {
1069 0 : if (boost::iequals(encrypt_mode_str, "all"))
1070 0 : mode = GlobalVrouter::CRYPT_ALL_TRAFFIC;
1071 0 : for (EncryptionTunnelEndpointList::const_iterator it = endpoint_list.begin();
1072 0 : it != endpoint_list.end(); it++) {
1073 0 : if (it->tunnel_remote_ip_address.compare(agent()->router_id().to_string()) == 0) {
1074 0 : continue;
1075 : }
1076 0 : crypt_tunnels_map.insert(CryptTunnelsPair(CryptTunnelKey(it->tunnel_remote_ip_address),
1077 0 : CryptTunnel(mode)));
1078 : }
1079 : }
1080 0 : crypt_tunnels_map_.swap(crypt_tunnels_map);
1081 0 : ChangeNotifyCryptTunnels(&crypt_tunnels_map, &crypt_tunnels_map_);
1082 1 : }
1083 :
1084 0 : void GlobalVrouter::DeleteCryptTunnelEndpointConfig() {
1085 0 : }
1086 :
1087 0 : bool GlobalVrouter::ChangeNotifyCryptTunnels(CryptTunnelsMap *old_value,
1088 : CryptTunnelsMap *new_value) {
1089 0 : bool change = false;
1090 0 : CryptTunnelsMap::iterator it_old = old_value->begin();
1091 0 : CryptTunnelsMap::iterator it_new = new_value->begin();
1092 0 : while (it_old != old_value->end() && it_new != new_value->end()) {
1093 0 : if (it_old->first < it_new->first) {
1094 : // old entry is deleted
1095 0 : DeleteCryptTunnelEndpoint(it_old);
1096 0 : change = true;
1097 0 : it_old++;
1098 0 : } else if (it_new->first < it_old->first) {
1099 : // new entry
1100 0 : AddCryptTunnelEndpoint(it_new);
1101 0 : change = true;
1102 0 : it_new++;
1103 0 : } else if (it_new->second == it_old->second) {
1104 : // no change in entry
1105 0 : it_old++;
1106 0 : it_new++;
1107 : } else {
1108 : // change in entry
1109 0 : ChangeCryptTunnelEndpoint(it_old, it_new);
1110 0 : change = true;
1111 0 : it_old++;
1112 0 : it_new++;
1113 : }
1114 : }
1115 :
1116 : // delete remaining old entries
1117 0 : for (; it_old != old_value->end(); ++it_old) {
1118 0 : DeleteCryptTunnelEndpoint(it_old);
1119 0 : change = true;
1120 : }
1121 :
1122 : // add remaining new entries
1123 0 : for (; it_new != new_value->end(); ++it_new) {
1124 0 : AddCryptTunnelEndpoint(it_new);
1125 0 : change = true;
1126 : }
1127 :
1128 0 : return change;
1129 : }
1130 :
1131 0 : void GlobalVrouter::AddCryptTunnelEndpoint(const CryptTunnelsMap::iterator &it) {
1132 0 : bool crypt_traffic = false;
1133 0 : if (it->second.mode == GlobalVrouter::CRYPT_ALL_TRAFFIC)
1134 0 : crypt_traffic = true;
1135 0 : agent()->crypt_tunnel_table()->Create(it->first, crypt_traffic);
1136 0 : }
1137 :
1138 0 : void GlobalVrouter::DeleteCryptTunnelEndpoint(const CryptTunnelsMap::iterator &it) {
1139 0 : agent()->crypt_tunnel_table()->Delete(it->first);
1140 0 : }
1141 :
1142 0 : void GlobalVrouter::ChangeCryptTunnelEndpoint(const CryptTunnelsMap::iterator &old_it,
1143 : const CryptTunnelsMap::iterator &new_it) {
1144 0 : AddCryptTunnelEndpoint(new_it);
1145 0 : }
1146 :
1147 0 : void PortConfig::Trim() {
1148 0 : if (port_range.size() != 0) {
1149 0 : port_count = 0;
1150 : }
1151 :
1152 : //Only port range specified
1153 : //nothing more to be done
1154 0 : if (port_count != 0) {
1155 0 : return;
1156 : }
1157 :
1158 0 : for (uint16_t index = 0; index < port_range.size(); index++) {
1159 : //Ignore invalid range
1160 0 : if (port_range[index].port_start > port_range[index].port_end) {
1161 0 : port_range[index].port_start = 0;
1162 0 : port_range[index].port_end = 0;
1163 : }
1164 :
1165 0 : if (port_range[index].port_start == 0 &&
1166 0 : port_range[index].port_end == 0) {
1167 0 : continue;
1168 : }
1169 :
1170 : //Check if given range is a subset or intersecting with any other range
1171 0 : for (uint16_t sub_index = 0; sub_index < port_range.size(); sub_index++) {
1172 0 : if (index == sub_index) {
1173 0 : continue;
1174 : }
1175 :
1176 : //Two ranges are same
1177 0 : if (port_range[index].port_start ==
1178 0 : port_range[sub_index].port_start &&
1179 0 : port_range[index].port_end == port_range[sub_index].port_end) {
1180 0 : port_range[index].port_start = 0;
1181 0 : port_range[index].port_end = 0;
1182 0 : break;
1183 : }
1184 :
1185 : //Range is a subset of other range
1186 0 : if (port_range[index].port_start >=
1187 0 : port_range[sub_index].port_start &&
1188 0 : port_range[index].port_end <= port_range[sub_index].port_end) {
1189 0 : port_range[index].port_start = 0;
1190 0 : port_range[index].port_end = 0;
1191 0 : break;
1192 : }
1193 :
1194 : //Overlapping range with index range lesser than sub index range
1195 : //Ex 10-15, 15-20
1196 0 : if (port_range[index].port_start <=
1197 0 : port_range[sub_index].port_start &&
1198 0 : port_range[index].port_end >=
1199 0 : port_range[sub_index].port_start &&
1200 0 : port_range[index].port_end < port_range[sub_index].port_end) {
1201 0 : port_range[index].port_end = port_range[sub_index].port_start;
1202 0 : port_range[sub_index].port_start =
1203 0 : port_range[sub_index].port_start + 1;
1204 : }
1205 : }
1206 : }
1207 :
1208 0 : port_count = 0;
1209 : //Update count
1210 0 : std::vector<PortRange>::iterator it = port_range.begin();
1211 0 : while (it != port_range.end()) {
1212 0 : std::vector<PortRange>::iterator prev_it = it++;
1213 0 : if (prev_it->port_end == 0 &&
1214 0 : prev_it->port_start == 0) {
1215 0 : continue;
1216 : }
1217 :
1218 0 : port_count += (prev_it->port_end - prev_it->port_start) + 1;
1219 : }
1220 : }
|