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