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 : #include <sys/types.h>
7 : #include <boost/uuid/uuid_io.hpp>
8 : #include "base/address_util.h"
9 : #include "init/agent_init.h"
10 : #include "oper/interface_common.h"
11 : #include "services/dns_proto.h"
12 : #include "bind/bind_resolver.h"
13 : #include "cmn/agent_cmn.h"
14 : #include "init/agent_param.h"
15 : #include "ifmap/ifmap_link.h"
16 : #include "ifmap/ifmap_table.h"
17 : #include "pkt/pkt_init.h"
18 : #include "controller/controller_dns.h"
19 : #include "oper/global_qos_config.h"
20 : #include "oper/vn.h"
21 : #include "oper/route_common.h"
22 : #include <fstream>
23 :
24 : const Ip4Address DnsProto::ip4_unspec_(0);
25 : const Ip6Address DnsProto::ip6_unspec_ = Ip6Address::from_string("::");
26 :
27 2 : void DnsProto::IoShutdown() {
28 2 : BindResolver::Shutdown();
29 :
30 2 : for (DnsBindQueryMap::iterator it = dns_query_map_.begin();
31 2 : it != dns_query_map_.end(); ) {
32 0 : DnsBindQueryMap::iterator next = it++;
33 0 : delete it->second;
34 0 : it = next;
35 : }
36 :
37 2 : curr_vm_requests_.clear();
38 : // Following tables should be deleted when all VMs are gone
39 2 : assert(update_set_.empty());
40 2 : assert(all_vms_.empty());
41 2 : }
42 :
43 2 : void DnsProto::ConfigInit() {
44 2 : BuildDefaultServerList();
45 2 : default_slist_timer_->Start(kDnsDefaultSlistInterval,
46 : boost::bind(&DnsProto::BuildDefaultServerList,
47 : this));
48 2 : std::vector<BindResolver::DnsServer> dns_servers;
49 6 : for (int i = 0; i < MAX_XMPP_SERVERS; i++) {
50 4 : std::string server = agent()->dns_server(i);
51 4 : if (server != "")
52 2 : dns_servers.push_back(BindResolver::DnsServer(
53 2 : server, agent()->dns_server_port(i)));
54 4 : }
55 2 : GlobalQosConfig* qos = NULL;
56 2 : uint8_t dscp = 0;
57 2 : if (agent_->oper_db()) {
58 2 : qos = agent_->oper_db()->global_qos_config();
59 : }
60 2 : if (qos && qos->control_dscp() != GlobalQosConfig::kInvalidDscp) {
61 2 : dscp = qos->dns_dscp();
62 : }
63 4 : BindResolver::Init(*agent()->event_manager()->io_service(), dns_servers,
64 2 : agent()->params()->dns_client_port(),
65 : boost::bind(&DnsProto::SendDnsIpc, this, _1, _2), dscp);
66 2 : }
67 :
68 2 : DnsProto::DnsProto(Agent *agent, boost::asio::io_context &io) :
69 : Proto(agent, "Agent::Services", PktHandler::DNS, io),
70 2 : xid_(0), timeout_(agent->params()->dns_timeout()),
71 4 : max_retries_(agent->params()->dns_max_retries()) {
72 : // limit the number of entries in the workqueue
73 2 : work_queue_.SetSize(agent->params()->services_queue_limit());
74 2 : work_queue_.SetBounded(true);
75 2 : def_server_list_.clear();
76 2 : default_slist_timer_ = TimerManager::CreateTimer(io, "DnsDefSlistTimer",
77 : TaskScheduler::GetInstance()->
78 : GetTaskId("Agent::Services"), PktHandler::DNS);
79 :
80 2 : lid_ = agent->interface_table()->Register(
81 : boost::bind(&DnsProto::InterfaceNotify, this, _2));
82 2 : Vnlid_ = agent->vn_table()->Register(
83 : boost::bind(&DnsProto::VnNotify, this, _2));
84 2 : if (agent->tsn_enabled()) {
85 0 : vrf_table_listener_id_ =
86 0 : agent->vrf_table()->Register(boost::bind(&DnsProto::VrfNotify,
87 : this, _2));
88 : }
89 2 : agent->domain_config_table()->RegisterIpamCb(
90 : boost::bind(&DnsProto::IpamNotify, this, _1));
91 2 : agent->domain_config_table()->RegisterVdnsCb(
92 : boost::bind(&DnsProto::VdnsNotify, this, _1));
93 : agent->interface_table()->set_update_floatingip_cb
94 2 : (boost::bind(&DnsProto::UpdateFloatingIp, this, _1, _2, _3, _4));
95 :
96 : AgentDnsXmppChannel::set_dns_message_handler_cb
97 2 : (boost::bind(&DnsProto::SendDnsUpdateIpc, this, _1, _2, _3, _4));
98 : AgentDnsXmppChannel::set_dns_xmpp_event_handler_cb
99 2 : (boost::bind(&DnsProto::SendDnsUpdateIpc, this, _1));
100 2 : }
101 :
102 4 : DnsProto::~DnsProto() {
103 4 : }
104 :
105 2 : void DnsProto::Shutdown() {
106 2 : agent_->interface_table()->Unregister(lid_);
107 2 : agent_->vn_table()->Unregister(Vnlid_);
108 2 : if (agent_->tsn_enabled()) {
109 0 : agent_->vrf_table()->Unregister(vrf_table_listener_id_);
110 : }
111 2 : default_slist_timer_->Cancel();
112 2 : TimerManager::DeleteTimer(default_slist_timer_);
113 2 : }
114 :
115 2 : bool DnsProto::BuildDefaultServerList() {
116 2 : def_server_list_ = BuildDefaultServerListImpl(); // assign new contents
117 2 : return true;
118 : }
119 :
120 0 : std::vector<IpAddress> DnsProto::GetDefaultServerList() {
121 0 : return def_server_list_;
122 : }
123 :
124 338 : ProtoHandler *DnsProto::AllocProtoHandler(boost::shared_ptr<PktInfo> info,
125 : boost::asio::io_context &io) {
126 338 : return new DnsHandler(agent(), info, io);
127 : }
128 :
129 1421 : void DnsProto::InterfaceNotify(DBEntryBase *entry) {
130 1421 : Interface *itf = static_cast<Interface *>(entry);
131 1421 : if (itf->type() != Interface::VM_INTERFACE)
132 21 : return;
133 :
134 1400 : const VmInterface *vmitf = static_cast<VmInterface *>(entry);
135 1400 : if (entry->IsDeleted()) {
136 169 : SendDnsUpdateIpc(NULL, DnsAgentXmpp::Update, vmitf, false);
137 169 : SendDnsUpdateIpc(NULL, DnsAgentXmpp::Update, vmitf, true);
138 169 : all_vms_.erase(vmitf);
139 169 : DNS_BIND_TRACE(DnsBindTrace, "Vm Interface deleted : " <<
140 : vmitf->vm_name());
141 : // remove floating ip entries from fip list
142 169 : const VmInterface::FloatingIpList &fip = vmitf->floating_ip_list();
143 338 : for (VmInterface::FloatingIpSet::iterator it = fip.list_.begin(),
144 338 : next = fip.list_.begin(); it != fip.list_.end(); it = next) {
145 0 : ++next;
146 0 : UpdateFloatingIp(vmitf, it->vn_.get(), it->floating_ip_,true);
147 : }
148 : } else {
149 1231 : autogen::VirtualDnsType vdns_type;
150 1231 : std::string vdns_name;
151 1231 : GetVdnsData(vmitf->vn(), vmitf->primary_ip_addr(),
152 : vmitf->primary_ip6_addr(),
153 : vdns_name, vdns_type);
154 1231 : VmDataMap::iterator it = all_vms_.find(vmitf);
155 1231 : if (it == all_vms_.end()) {
156 169 : if (!UpdateDnsEntry(vmitf, vmitf->vn(), vmitf->vm_name(), vdns_name,
157 : vmitf->primary_ip_addr(), vmitf->primary_ip6_addr(),
158 : false, false))
159 0 : vdns_name = "";
160 169 : IpVdnsMap vmdata;
161 169 : vmdata.insert(IpVdnsPair(vmitf->primary_ip_addr().to_ulong(), vdns_name));
162 169 : all_vms_.insert(VmDataPair(vmitf, vmdata));
163 169 : DNS_BIND_TRACE(DnsBindTrace, "Vm Interface added : " <<
164 : vmitf->vm_name());
165 169 : } else {
166 1062 : CheckForUpdate(it->second, vmitf, vmitf->vn(),
167 : vmitf->primary_ip_addr(), vmitf->primary_ip6_addr(),
168 : vdns_name, vdns_type);
169 : }
170 :
171 : // Floating ip records follow the floating ip configuration, not the
172 : // forwarding state of the interface; publish every configured entry,
173 : // including the ones that are not installed because the interface is
174 : // inactive (instance powered off). Withdrawal happens when the entry
175 : // leaves the configuration, from CleanupFloatingIpList().
176 : // If tenant name is also required in the fip name, it may not be
177 : // available during activate if the vm interface doesnt have vn at
178 : // that time. Invoke Update here to handle that case.
179 1231 : if (vmitf->vn()) {
180 984 : const VmInterface::FloatingIpList &fip = vmitf->floating_ip_list();
181 984 : for (VmInterface::FloatingIpSet::iterator it = fip.list_.begin();
182 1175 : it != fip.list_.end(); ++it) {
183 : // FloatingIp::Copy() assigns vn_ only while it is NULL, so a
184 : // reference to an already deleted VnEntry survives here.
185 : // Republishing on such an entry would resurrect the record
186 : // VnNotify() has just withdrawn, and nothing would withdraw it
187 : // again - VnNotify() does not fire twice for the same VN and
188 : // CleanupFloatingIpList() cannot resolve a deleted VN.
189 382 : if (it->del_pending() == false && it->vn_.get() != NULL &&
190 191 : it->vn_->IsDeleted() == false) {
191 191 : UpdateFloatingIp(vmitf, it->vn_.get(),
192 191 : it->floating_ip_, false);
193 : }
194 : }
195 : }
196 1231 : }
197 : }
198 :
199 269 : void DnsProto::VnNotify(DBEntryBase *entry) {
200 269 : const VnEntry *vn = static_cast<const VnEntry *>(entry);
201 269 : if (vn->IsDeleted()) {
202 : // remove floating ip entries from this vn in floating ip list
203 : // Ip4Address is the smallest address
204 69 : IpAddress ip_key = Ip4Address(0);
205 69 : DnsFipEntryPtr key(new DnsFipEntry(vn, ip_key, NULL));
206 69 : DnsFipSet::iterator it = fip_list_.upper_bound(key);
207 69 : while (it != fip_list_.end()) {
208 4 : DnsFipEntry *entry = (*it).get();
209 4 : if (entry->vn_ != vn) {
210 4 : break;
211 : }
212 0 : ++it;
213 0 : UpdateFloatingIp(entry->interface_, entry->vn_,
214 0 : entry->floating_ip_, true);
215 : }
216 69 : return;
217 69 : }
218 200 : if (vn->GetVnIpam().size() == 0)
219 124 : return;
220 76 : DNS_BIND_TRACE(DnsBindTrace, "Vn Notify : " << vn->GetName());
221 636 : for (VmDataMap::iterator it = all_vms_.begin(); it != all_vms_.end(); ++it) {
222 560 : if (it->first->vn() == vn) {
223 156 : std::string vdns_name;
224 156 : autogen::VirtualDnsType vdns_type;
225 156 : GetVdnsData(vn, it->first->primary_ip_addr(),
226 156 : it->first->primary_ip6_addr(),
227 : vdns_name, vdns_type);
228 156 : CheckForUpdate(it->second, it->first, it->first->vn(),
229 156 : it->first->primary_ip_addr(),
230 156 : it->first->primary_ip6_addr(),
231 : vdns_name, vdns_type);
232 156 : }
233 : }
234 76 : IpAddress ip_key = Ip4Address(0);
235 76 : DnsFipEntryPtr key(new DnsFipEntry(vn, ip_key, NULL));
236 76 : DnsFipSet::iterator it = fip_list_.upper_bound(key);
237 76 : while (it != fip_list_.end()) {
238 1 : std::string fip_vdns_name;
239 1 : DnsFipEntry *entry = (*it).get();
240 1 : if (entry->vn_ != vn) {
241 1 : break;
242 : }
243 0 : autogen::VirtualDnsType fip_vdns_type;
244 0 : Ip4Address ip4 = ip4_unspec_;
245 0 : Ip6Address ip6 = ip6_unspec_;
246 0 : if (entry->floating_ip_.is_v4()) {
247 0 : ip4 = entry->floating_ip_.to_v4();
248 : }
249 0 : if (entry->floating_ip_.is_v6()) {
250 0 : ip6 = entry->floating_ip_.to_v6();
251 : }
252 0 : GetVdnsData(entry->vn_, ip4, ip6,
253 : fip_vdns_name, fip_vdns_type);
254 0 : CheckForFipUpdate(entry, fip_vdns_name, fip_vdns_type);
255 0 : ++it;
256 1 : }
257 76 : }
258 :
259 0 : void DnsProto::VrfNotify(DBEntryBase *entry) {
260 0 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
261 0 : if (vrf->GetName() == agent_->fabric_vrf_name())
262 0 : return;
263 0 : MacAddress address(agent_->vhost_interface()->mac());
264 :
265 0 : if (entry->IsDeleted()) {
266 0 : BridgeAgentRouteTable::Delete(agent_->local_peer(), vrf->GetName(),
267 : address, -1);
268 0 : return;
269 : }
270 :
271 0 : if (vrf->vn()) {
272 0 : BridgeAgentRouteTable::AddBridgeReceiveRoute(agent_->local_peer(),
273 : vrf->GetName(),
274 : address,
275 : vrf->vn()->GetName(),
276 : "pkt0", true);
277 : }
278 : }
279 :
280 116 : void DnsProto::IpamNotify(IFMapNode *node) {
281 116 : if (node->IsDeleted())
282 91 : return;
283 25 : DNS_BIND_TRACE(DnsBindTrace, "Ipam Notify : " << node->name());
284 25 : ProcessNotify(node->name(), node->IsDeleted(), true);
285 : }
286 :
287 0 : void DnsProto::VdnsNotify(IFMapNode *node) {
288 0 : DNS_BIND_TRACE(DnsBindTrace, "Vdns Notify : " << node->name());
289 : // Update any existing records prior to checking for new ones
290 0 : if (!node->IsDeleted()) {
291 : autogen::VirtualDns *virtual_dns =
292 0 : static_cast <autogen::VirtualDns *> (node->GetObject());
293 0 : autogen::VirtualDnsType vdns_type = virtual_dns->data();
294 0 : std::string name = node->name();
295 0 : MoveVDnsEntry(NULL, name, name, vdns_type, false);
296 0 : }
297 0 : ProcessNotify(node->name(), node->IsDeleted(), false);
298 0 : }
299 :
300 25 : void DnsProto::ProcessNotify(std::string name, bool is_deleted, bool is_ipam) {
301 194 : for (VmDataMap::iterator it = all_vms_.begin(); it != all_vms_.end(); ++it) {
302 169 : std::string vdns_name;
303 169 : autogen::VirtualDnsType vdns_type;
304 169 : GetVdnsData(it->first->vn(), it->first->primary_ip_addr(),
305 169 : it->first->primary_ip6_addr(), vdns_name, vdns_type);
306 : // in case of VDNS delete, clear the name
307 169 : if (!is_ipam && is_deleted && vdns_name == name)
308 0 : vdns_name.clear();
309 169 : CheckForUpdate(it->second, it->first, it->first->vn(),
310 169 : it->first->primary_ip_addr(),
311 169 : it->first->primary_ip6_addr(),
312 : vdns_name, vdns_type);
313 169 : }
314 25 : DnsFipSet::iterator it = fip_list_.begin();
315 25 : while (it != fip_list_.end()) {
316 0 : std::string fip_vdns_name;
317 0 : DnsFipEntry *entry = (*it).get();
318 0 : autogen::VirtualDnsType fip_vdns_type;
319 0 : Ip4Address ip4 = ip4_unspec_;
320 0 : Ip6Address ip6 = ip6_unspec_;
321 0 : if (entry->floating_ip_.is_v4()) {
322 0 : ip4 = entry->floating_ip_.to_v4();
323 : }
324 0 : if (entry->floating_ip_.is_v6()) {
325 0 : ip6 = entry->floating_ip_.to_v6();
326 : }
327 0 : GetVdnsData(entry->vn_, ip4, ip6,
328 : fip_vdns_name, fip_vdns_type);
329 0 : CheckForFipUpdate(entry, fip_vdns_name, fip_vdns_type);
330 0 : ++it;
331 0 : }
332 25 : }
333 :
334 1387 : void DnsProto::CheckForUpdate(IpVdnsMap &ipvdns, const VmInterface *vmitf,
335 : const VnEntry *vn, const Ip4Address &ip,
336 : const Ip6Address &ip6, std::string &vdns_name,
337 : const autogen::VirtualDnsType &vdns_type) {
338 1387 : IpVdnsMap::iterator vmdata_it = ipvdns.find(ip.to_ulong());
339 1387 : if (vmdata_it == ipvdns.end()) {
340 0 : if (UpdateDnsEntry(vmitf, vn, vmitf->vm_name(),
341 : vdns_name, ip, ip6, false, false))
342 0 : ipvdns.insert(IpVdnsPair(ip.to_ulong(), vdns_name));
343 : else
344 0 : ipvdns.insert(IpVdnsPair(ip.to_ulong(), ""));
345 0 : return;
346 : }
347 1387 : if (vmdata_it->second.empty() && vmdata_it->second != vdns_name) {
348 0 : if (UpdateDnsEntry(vmitf, vn, vmitf->vm_name(),
349 : vdns_name, ip, ip6, false, false))
350 0 : vmdata_it->second = vdns_name;
351 1387 : } else if (vmdata_it->second != vdns_name) {
352 0 : if (MoveVDnsEntry(vmitf, vdns_name, vmdata_it->second,
353 : vdns_type, false))
354 0 : vmdata_it->second = vdns_name;
355 : }
356 : }
357 :
358 274 : void DnsProto::CheckForFipUpdate(DnsFipEntry *entry, std::string &vdns_name,
359 : const autogen::VirtualDnsType &vdns_type) {
360 274 : if (entry->vdns_name_.empty() && entry->vdns_name_ != vdns_name) {
361 0 : std::string fip_name;
362 0 : if (!GetFipName(entry->interface_, vdns_type,
363 0 : entry->floating_ip_, fip_name))
364 0 : vdns_name = "";
365 :
366 0 : Ip4Address ip4 = ip4_unspec_;
367 0 : Ip6Address ip6 = ip6_unspec_;
368 0 : if (entry->floating_ip_.is_v4()) {
369 0 : ip4 = entry->floating_ip_.to_v4();
370 : }
371 0 : if (entry->floating_ip_.is_v6()) {
372 0 : ip6 = entry->floating_ip_.to_v6();
373 : }
374 0 : if (UpdateDnsEntry(entry->interface_, entry->vn_, fip_name,
375 : vdns_name, ip4, ip6, true, false)) {
376 0 : entry->vdns_name_.assign(vdns_name);
377 0 : entry->fip_name_ = fip_name;
378 : }
379 274 : } else if (entry->vdns_name_ != vdns_name) {
380 0 : if (MoveVDnsEntry(entry->interface_, vdns_name, entry->vdns_name_,
381 : vdns_type, true)) {
382 0 : entry->vdns_name_.assign(vdns_name);
383 : }
384 : }
385 274 : }
386 :
387 : // Send A & PTR record entries
388 0 : bool DnsProto::SendUpdateDnsEntry(const VmInterface *vmitf,
389 : const std::string &name,
390 : const Ip4Address &ip, uint32_t plen,
391 : const Ip6Address &ip6, uint32_t plen6,
392 : const std::string &vdns_name,
393 : const autogen::VirtualDnsType &vdns_type,
394 : bool is_floating, bool is_delete) {
395 0 : if (!name.size() || !vdns_type.dynamic_records_from_client) {
396 0 : DNS_BIND_TRACE(DnsBindTrace, "Not adding DNS entry; Name = " <<
397 : name << "Dynamic records allowed = " <<
398 : (vdns_type.dynamic_records_from_client ? "yes" : "no"));
399 0 : return false;
400 : }
401 :
402 0 : DnsUpdateData *data = new DnsUpdateData();
403 0 : data->virtual_dns = vdns_name;
404 0 : data->zone = vdns_type.domain_name;
405 :
406 0 : std::string vm_uuid;
407 0 : if (vmitf) {
408 0 : vm_uuid = boost::uuids::to_string(vmitf->GetUuid());
409 : }
410 :
411 : // Add a DNS record
412 0 : DnsItem item;
413 0 : if (!ip.is_unspecified()) {
414 0 : item.eclass = is_delete ? DNS_CLASS_NONE : DNS_CLASS_IN;
415 0 : item.type = DNS_A_RECORD;
416 0 : item.ttl = is_delete ? 0 : vdns_type.default_ttl_seconds;
417 0 : item.name = name;
418 0 : item.vm_uuid = vm_uuid;
419 0 : boost::system::error_code ec;
420 0 : item.data = ip.to_string(ec);
421 0 : data->items.push_back(item);
422 : }
423 :
424 0 : DnsItem ip6_item;
425 0 : if (!ip6.is_unspecified()) {
426 0 : ip6_item.eclass = is_delete ? DNS_CLASS_NONE : DNS_CLASS_IN;
427 0 : ip6_item.type = DNS_AAAA_RECORD;
428 0 : ip6_item.ttl = is_delete ? 0 : vdns_type.default_ttl_seconds;
429 0 : ip6_item.name = name;
430 0 : ip6_item.vm_uuid = vm_uuid;
431 0 : boost::system::error_code ec;
432 0 : ip6_item.data = ip6.to_string(ec);
433 0 : data->items.push_back(ip6_item);
434 : }
435 :
436 0 : if (data->items.size()) {
437 0 : DNS_BIND_TRACE(DnsBindTrace,
438 : "DNS update sent for : " << item.ToString() <<
439 : " IPv6 : " << ip6_item.ToString() <<
440 : " VDNS : " << data->virtual_dns <<
441 : " Zone : " << data->zone);
442 0 : SendDnsUpdateIpc(data, DnsAgentXmpp::Update, vmitf, is_floating);
443 : } else {
444 0 : DNS_BIND_TRACE(DnsBindTrace, "Not adding DNS entry; Name = " <<
445 : name << "Address unspecified");
446 0 : return false;
447 : }
448 :
449 : // Add a PTR record as well
450 0 : DnsUpdateData *ptr_data = new DnsUpdateData();
451 0 : ptr_data->virtual_dns = vdns_name;
452 0 : BindUtil::GetReverseZone(ip, plen, ptr_data->zone);
453 :
454 0 : item.type = DNS_PTR_RECORD;
455 0 : item.data.swap(item.name);
456 0 : item.name = BindUtil::GetPtrNameFromAddr(ip);
457 0 : ptr_data->items.push_back(item);
458 :
459 0 : DNS_BIND_TRACE(DnsBindTrace, "DNS update sent for : " << item.ToString() <<
460 : " VDNS : " << ptr_data->virtual_dns <<
461 : " Zone : " << ptr_data->zone);
462 0 : SendDnsUpdateIpc(ptr_data, DnsAgentXmpp::Update, vmitf, is_floating);
463 :
464 : // Add a PTR record for IPv6, if present
465 0 : if (!ip6.is_unspecified()) {
466 0 : DnsUpdateData *ptr6_data = new DnsUpdateData();
467 0 : ptr6_data->virtual_dns = vdns_name;
468 0 : BindUtil::GetReverseZone(ip6, plen6, ptr6_data->zone);
469 :
470 0 : ip6_item.type = DNS_PTR_RECORD;
471 0 : ip6_item.data.swap(ip6_item.name);
472 :
473 0 : ip6_item.name = BindUtil::GetPtrNameFromAddr(ip6);
474 0 : ptr6_data->items.push_back(ip6_item);
475 :
476 0 : DNS_BIND_TRACE(DnsBindTrace, "DNS update sent for : " << ip6_item.ToString() <<
477 : " VDNS : " << ptr6_data->virtual_dns <<
478 : " Zone : " << ptr6_data->zone);
479 0 : SendDnsUpdateIpc(ptr6_data, DnsAgentXmpp::Update, vmitf, is_floating);
480 : }
481 :
482 0 : return true;
483 0 : }
484 :
485 : // Update the floating ip entries
486 500 : bool DnsProto::UpdateFloatingIp(const VmInterface *vmitf, const VnEntry *vn,
487 : const IpAddress &ip, bool is_deleted) {
488 500 : Ip4Address ip4 = ip4_unspec_;
489 500 : Ip6Address ip6 = ip6_unspec_;
490 500 : if (ip.is_v6()) {
491 0 : ip6 = ip.to_v6();
492 : }
493 500 : if (ip.is_v4()) {
494 500 : ip4 = ip.to_v4();
495 : }
496 500 : bool is_floating = true;
497 500 : std::string vdns_name;
498 500 : autogen::VirtualDnsType vdns_type;
499 500 : GetVdnsData(vn, ip4, ip6, vdns_name, vdns_type);
500 500 : DnsFipEntryPtr key(new DnsFipEntry(vn, ip, vmitf));
501 500 : DnsFipSet::iterator it = fip_list_.find(key);
502 500 : if (it == fip_list_.end()) {
503 113 : if (is_deleted)
504 0 : return true;
505 113 : std::string fip_name;
506 113 : if (!GetFipName(vmitf, vdns_type, ip, fip_name))
507 0 : vdns_name = "";
508 113 : if (!UpdateDnsEntry(vmitf, vn, fip_name,
509 : vdns_name, ip4, ip6, is_floating, false))
510 0 : vdns_name = "";
511 113 : key.get()->vdns_name_ = vdns_name;
512 113 : key.get()->fip_name_ = fip_name;
513 113 : fip_list_.insert(key);
514 113 : } else {
515 387 : if (is_deleted) {
516 113 : std::string fip_name;
517 113 : UpdateDnsEntry(vmitf, vn, (*it)->fip_name_,
518 113 : (*it)->vdns_name_, ip4, ip6, is_floating, true);
519 113 : fip_list_.erase(key);
520 113 : } else {
521 274 : DnsFipEntry *entry = (*it).get();
522 274 : CheckForFipUpdate(entry, vdns_name, vdns_type);
523 : }
524 : }
525 500 : return true;
526 500 : }
527 :
528 395 : bool DnsProto::UpdateDnsEntry(const VmInterface *vmitf, const VnEntry *vn,
529 : const std::string &vm_name,
530 : const std::string &vdns_name,
531 : const Ip4Address &ip,
532 : const Ip6Address &ip6,
533 : bool is_floating, bool is_deleted) {
534 395 : if (!vdns_name.empty()) {
535 0 : uint32_t plen = 0;
536 0 : const std::vector<VnIpam> &ipam = vn->GetVnIpam();
537 : unsigned int i;
538 0 : if (!ip.is_unspecified()) {
539 0 : for (i = 0; i < ipam.size(); ++i) {
540 0 : if (ipam[i].IsV4() &&
541 0 : IsIp4SubnetMember(ip, ipam[i].ip_prefix.to_v4(), ipam[i].plen)) {
542 0 : plen = ipam[i].plen;
543 0 : break;
544 : }
545 : }
546 0 : if (i == ipam.size()) {
547 0 : DNS_BIND_TRACE(DnsBindTrace, "UpdateDnsEntry for VM <" <<
548 : vm_name << "> not done for vn <" <<
549 : vn->GetName() << "> IPAM doesnt have Ipv4 subnet; " <<
550 : ((is_deleted)? "delete" : "update"));
551 0 : return false;
552 : }
553 : }
554 :
555 0 : uint32_t plen6 = 0;
556 0 : if (!ip6.is_unspecified()) {
557 0 : for (i = 0; i < ipam.size(); ++i) {
558 0 : if (ipam[i].IsV6() &&
559 0 : IsIp6SubnetMember(ip6, ipam[i].ip_prefix.to_v6(), ipam[i].plen)) {
560 0 : plen6 = ipam[i].plen;
561 0 : break;
562 : }
563 : }
564 0 : if (i == ipam.size()) {
565 0 : DNS_BIND_TRACE(DnsBindTrace, "UpdateDnsEntry for VM <" <<
566 : vm_name << "> not done for vn <" <<
567 : vn->GetName() << "> IPAM doesnt have Ipv6 subnet; " <<
568 : ((is_deleted)? "delete" : "update"));
569 0 : return false;
570 : }
571 : }
572 :
573 0 : autogen::VirtualDnsType vdns_type;
574 0 : if (agent_->domain_config_table()->GetVDns(vdns_name, &vdns_type)) {
575 0 : return SendUpdateDnsEntry(vmitf, vm_name, ip, plen, ip6, plen6,
576 : vdns_name, vdns_type, is_floating,
577 0 : is_deleted);
578 : } else {
579 0 : DNS_BIND_TRACE(DnsBindTrace, "UpdateDnsEntry for VM <" <<
580 : vm_name << "> entry not " <<
581 : ((is_deleted)? "deleted; " : "updated; ") <<
582 : "VDNS info for " << vdns_name << " not present");
583 0 : return false;
584 : }
585 0 : }
586 :
587 395 : return true;
588 : }
589 :
590 : // Move DNS entries for a VM from one VDNS to another
591 0 : bool DnsProto::MoveVDnsEntry(const VmInterface *vmitf,
592 : std::string &new_vdns_name,
593 : std::string &old_vdns_name,
594 : const autogen::VirtualDnsType &vdns_type,
595 : bool is_floating) {
596 0 : std::string name = (vmitf ? vmitf->vm_name() : "All Vms");
597 0 : DNS_BIND_TRACE(DnsBindTrace, "VDNS modify for VM <" << name <<
598 : " old VDNS : " << old_vdns_name <<
599 : " new VDNS : " << new_vdns_name <<
600 : " ttl : " << vdns_type.default_ttl_seconds <<
601 : " floating : " << (is_floating ? "yes" : "no"));
602 0 : SendDnsUpdateIpc(vmitf, new_vdns_name,
603 0 : old_vdns_name, vdns_type.domain_name,
604 0 : (uint32_t)vdns_type.default_ttl_seconds, is_floating);
605 0 : return true;
606 0 : }
607 :
608 2056 : bool DnsProto::GetVdnsData(const VnEntry *vn, const Ip4Address &v4_addr,
609 : const Ip6Address &v6_addr, std::string &vdns_name,
610 : autogen::VirtualDnsType &vdns_type) {
611 2056 : if (!vn)
612 277 : return false;
613 :
614 1779 : autogen::IpamType ipam_type;
615 1779 : if ((!v4_addr.to_ulong() ||
616 3595 : !vn->GetIpamVdnsData(v4_addr, &ipam_type, &vdns_type)) &&
617 1779 : (v6_addr.is_unspecified() ||
618 1816 : !vn->GetIpamVdnsData(v6_addr, &ipam_type, &vdns_type))) {
619 1779 : DNS_BIND_TRACE(DnsBindTrace, "Unable to retrieve VDNS data; VN : " <<
620 : vn->GetName() << " IPv4 : " << v4_addr.to_string() <<
621 : " IPv6 : " << v6_addr.to_string());
622 1779 : return false;
623 : }
624 :
625 0 : vdns_name = ipam_type.ipam_dns_server.virtual_dns_server_name;
626 0 : return true;
627 1779 : }
628 :
629 113 : bool DnsProto::GetFipName(const VmInterface *vmitf,
630 : const autogen::VirtualDnsType &vdns_type,
631 : const IpAddress &ip, std::string &fip_name) const {
632 : std::string fip_name_notation =
633 113 : boost::to_lower_copy(vdns_type.floating_ip_record);
634 :
635 113 : std::string name;
636 113 : if (fip_name_notation == "" ||
637 113 : fip_name_notation == "dashed-ip" ||
638 0 : fip_name_notation == "dashed-ip-tenant-name") {
639 113 : name = ip.to_string();
640 113 : boost::replace_all(name, ".", "-");
641 : } else {
642 0 : name = vmitf->vm_name();
643 : }
644 :
645 113 : if (fip_name_notation == "" ||
646 113 : fip_name_notation == "dashed-ip-tenant-name" ||
647 0 : fip_name_notation == "vm-name-tenant-name") {
648 113 : if (!vmitf->vn())
649 0 : return false;
650 113 : name += "." + vmitf->vn()->GetProject();
651 : }
652 :
653 113 : fip_name = name;
654 113 : return true;
655 113 : }
656 :
657 0 : uint16_t DnsProto::GetTransId() {
658 0 : return (++xid_ == 0 ? ++xid_ : xid_);
659 : }
660 :
661 0 : void DnsProto::SendDnsIpc(uint8_t *pkt, std::size_t length) {
662 0 : DnsIpc *ipc = new DnsIpc(pkt, length, 0, NULL, DnsProto::DNS_BIND_RESPONSE);
663 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::DNS, ipc);
664 0 : }
665 :
666 0 : void DnsProto::SendDnsIpc(InterTaskMessage cmd, uint16_t xid, uint8_t *msg,
667 : DnsHandler *handler) {
668 0 : DnsIpc *ipc = new DnsIpc(msg, 0, xid, handler, cmd);
669 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::DNS, ipc);
670 0 : }
671 :
672 338 : void DnsProto::SendDnsUpdateIpc(DnsUpdateData *data,
673 : DnsAgentXmpp::XmppType type,
674 : const VmInterface *vm, bool floating) {
675 338 : DnsUpdateIpc *ipc = new DnsUpdateIpc(type, data, vm, floating);
676 338 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::DNS, ipc);
677 338 : }
678 :
679 0 : void DnsProto::SendDnsUpdateIpc(const VmInterface *vm,
680 : const std::string &new_vdns,
681 : const std::string &old_vdns,
682 : const std::string &new_dom,
683 : uint32_t ttl, bool is_floating) {
684 : DnsUpdateIpc *ipc = new DnsUpdateIpc(vm, new_vdns, old_vdns, new_dom,
685 0 : ttl, is_floating);
686 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::DNS, ipc);
687 0 : }
688 :
689 0 : void DnsProto::SendDnsUpdateIpc(AgentDnsXmppChannel *channel) {
690 0 : DnsUpdateAllIpc *ipc = new DnsUpdateAllIpc(channel);
691 0 : agent_->pkt()->pkt_handler()->SendMessage(PktHandler::DNS, ipc);
692 0 : }
693 :
694 0 : void DnsProto::AddDnsQuery(uint16_t xid, DnsHandler *handler) {
695 0 : dns_query_map_.insert(DnsBindQueryPair(xid, handler));
696 0 : }
697 :
698 0 : void DnsProto::DelDnsQuery(uint16_t xid) {
699 0 : dns_query_map_.erase(xid);
700 0 : }
701 :
702 0 : bool DnsProto::IsDnsQueryInProgress(uint16_t xid) {
703 0 : return dns_query_map_.find(xid) != dns_query_map_.end();
704 : }
705 :
706 0 : bool DnsProto::IsDnsHandlerInUse(DnsHandler *handler) {
707 0 : for (DnsBindQueryMap::iterator it = dns_query_map_.begin();
708 0 : it != dns_query_map_.end(); it++) {
709 0 : if (it->second == handler) {
710 0 : return true;
711 : }
712 : }
713 0 : return false;
714 : }
715 :
716 0 : void DnsProto::DelDnsQueryHandler(DnsHandler *handler) {
717 0 : for (DnsBindQueryMap::iterator it = dns_query_map_.begin();
718 0 : it != dns_query_map_.end();) {
719 0 : if (it->second == handler) {
720 0 : dns_query_map_.erase(it++);
721 0 : continue;
722 : }
723 0 : ++it;
724 : }
725 0 : }
726 :
727 0 : DnsHandler *DnsProto::GetDnsQueryHandler(uint16_t xid) {
728 0 : DnsBindQueryMap::iterator it = dns_query_map_.find(xid);
729 0 : if (it != dns_query_map_.end())
730 0 : return it->second;
731 0 : return NULL;
732 : }
733 :
734 0 : void DnsProto::AddDnsQueryIndex(uint16_t xid, int16_t srv_idx) {
735 0 : dns_query_index_map_.insert(DnsBindQueryIndexPair(xid, srv_idx));
736 0 : }
737 :
738 0 : void DnsProto::DelDnsQueryIndex(uint16_t xid) {
739 0 : dns_query_index_map_.erase(xid);
740 0 : }
741 :
742 0 : int16_t DnsProto::GetDnsQueryServerIndex(uint16_t xid) {
743 0 : DnsBindQueryIndexMap::iterator it = dns_query_index_map_.find(xid);
744 0 : if (it != dns_query_index_map_.end())
745 0 : return it->second;
746 0 : return -1;
747 : }
748 :
749 :
750 0 : void DnsProto::AddVmRequest(DnsHandler::QueryKey *key) {
751 0 : curr_vm_requests_.insert(*key);
752 0 : }
753 :
754 0 : void DnsProto::DelVmRequest(DnsHandler::QueryKey *key) {
755 0 : curr_vm_requests_.erase(*key);
756 0 : }
757 :
758 0 : bool DnsProto::IsVmRequestDuplicate(DnsHandler::QueryKey *key) {
759 0 : return curr_vm_requests_.find(*key) != curr_vm_requests_.end();
760 : }
761 :
762 645 : DnsProto::DnsFipEntry::DnsFipEntry(const VnEntry *vn, const IpAddress &fip,
763 645 : const VmInterface *itf)
764 645 : : vn_(vn), floating_ip_(fip), interface_(itf) {
765 645 : }
766 :
767 1290 : DnsProto::DnsFipEntry::~DnsFipEntry() {
768 1290 : }
769 :
770 2510 : bool DnsProto::DnsFipEntryCmp::operator() (const DnsFipEntryPtr &lhs,
771 : const DnsFipEntryPtr &rhs) const {
772 2510 : return lhs->IsLess(rhs.get());
773 : }
774 :
775 2510 : bool DnsProto::DnsFipEntry::IsLess(const DnsFipEntry *rhs) const {
776 2510 : if (vn_ != rhs->vn_) {
777 701 : return vn_ < rhs->vn_;
778 : }
779 1809 : if (floating_ip_ != rhs->floating_ip_) {
780 0 : return floating_ip_ < rhs->floating_ip_;
781 : }
782 1809 : return interface_ < rhs->interface_;
783 : }
|