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