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 "base/logging.h" 7 : #include "base/task_trigger.h" 8 : #include <pugixml/pugixml.hpp> 9 : #include "agent/agent_xmpp_channel.h" 10 : 11 : #include "xml/xml_pugi.h" 12 : #include "xmpp/xmpp_connection.h" 13 : #include "xmpp/xmpp_server.h" 14 : #include "cmn/dns.h" 15 : #include "mgr/dns_mgr.h" 16 : #include "mgr/dns_oper.h" 17 : #include "bind/bind_util.h" 18 : #include "bind/bind_resolver.h" 19 : #include "bind/named_config.h" 20 : #include "bind/xmpp_dns_agent.h" 21 : #include "sandesh/sandesh_trace.h" 22 : #include "cmn/dns_types.h" 23 : 24 0 : DnsAgentXmppChannel:: DnsAgentXmppChannel(XmppChannel *channel, 25 0 : DnsAgentXmppChannelManager *mgr) 26 0 : : channel_(channel), mgr_(mgr) { 27 0 : channel_->RegisterReceive(xmps::DNS, 28 : boost::bind(&DnsAgentXmppChannel::ReceiveReq, this, _1)); 29 : 30 0 : } 31 : 32 0 : DnsAgentXmppChannel::~DnsAgentXmppChannel() { 33 0 : channel_->UnRegisterWriteReady(xmps::DNS); 34 0 : channel_->UnRegisterReceive(xmps::DNS); 35 0 : } 36 : 37 0 : void DnsAgentXmppChannel::Close() { 38 0 : UpdateDnsRecords(BindUtil::DELETE_UPDATE); 39 0 : if (mgr_) 40 0 : mgr_->RemoveChannel(channel_); 41 0 : } 42 : 43 0 : void DnsAgentXmppChannel::ReceiveReq(const XmppStanza::XmppMessage *msg) { 44 0 : if (msg && msg->type == XmppStanza::IQ_STANZA) { 45 0 : XmlBase *impl = msg->dom.get(); 46 0 : XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl); 47 0 : pugi::xml_node node = pugi->FindNode("dns"); 48 : DnsAgentXmpp::XmppType type; 49 0 : std::string source_name = msg->from; 50 : uint32_t xid; 51 : uint16_t code; 52 0 : std::unique_ptr<DnsUpdateData> rcv_data(new DnsUpdateData()); 53 0 : DnsUpdateData *data = rcv_data.get(); 54 0 : if (DnsAgentXmpp::DnsAgentXmppDecode(node, type, xid, code, data, source_name)) { 55 0 : if (type == DnsAgentXmpp::Update) { 56 0 : HandleAgentUpdate(std::move(rcv_data)); 57 : } 58 : } 59 0 : } 60 0 : } 61 : 62 0 : void DnsAgentXmppChannel::HandleAgentUpdate( 63 : std::unique_ptr<DnsUpdateData> rcv_data) { 64 0 : DnsUpdateData *data = rcv_data.get(); 65 0 : if (data->virtual_dns.empty() || data->zone.empty()) { 66 : // if key is not present, ignore the update 67 0 : return; 68 : } 69 0 : DataSet::iterator it = update_data_.find(data); 70 0 : if (it != update_data_.end()) { 71 0 : DnsUpdateData *xmpp_data = *it; 72 0 : for (DnsItems::iterator iter = data->items.begin(); 73 0 : iter != data->items.end();) { 74 : bool change; 75 0 : BindUtil::Operation op = BindUtil::ADD_UPDATE; 76 0 : if ((*iter).IsDelete()) { 77 0 : change = xmpp_data->DelItem(*iter); 78 0 : op = BindUtil::DELETE_UPDATE; 79 : } else { 80 0 : change = xmpp_data->AddItem(*iter, true); 81 0 : if (!change) { 82 0 : op = BindUtil::CHANGE_UPDATE; 83 0 : change = true; 84 : } 85 : } 86 : 87 0 : if (!change) { 88 0 : data->items.erase(iter++); 89 : } else { 90 : boost::shared_ptr<DnsAgentXmppChannelManager::RecordRequest> 91 : req(new DnsAgentXmppChannelManager::RecordRequest( 92 0 : op, GetDnsRecordName(data->virtual_dns, *iter), 93 0 : data->virtual_dns, *iter)); 94 0 : mgr_->EnqueueRecord(req); 95 0 : ++iter; 96 0 : } 97 : } 98 0 : if (!xmpp_data->items.size()) { 99 0 : update_data_.erase(xmpp_data); 100 0 : delete xmpp_data; 101 : } 102 : } else { 103 0 : for (DnsItems::iterator iter = data->items.begin(); 104 0 : iter != data->items.end();) { 105 0 : if ((*iter).IsDelete()) 106 0 : data->items.erase(iter++); 107 : else { 108 : boost::shared_ptr<DnsAgentXmppChannelManager::RecordRequest> 109 : req(new DnsAgentXmppChannelManager::RecordRequest( 110 : BindUtil::ADD_UPDATE, 111 0 : GetDnsRecordName(data->virtual_dns, *iter), 112 0 : data->virtual_dns, *iter)); 113 0 : mgr_->EnqueueRecord(req); 114 0 : ++iter; 115 0 : } 116 : } 117 0 : update_data_.insert(data); 118 0 : rcv_data.release(); 119 : } 120 : } 121 : 122 0 : void DnsAgentXmppChannel::UpdateDnsRecords(BindUtil::Operation op) { 123 0 : for (DataSet::iterator it = update_data_.begin(); 124 0 : it != update_data_.end(); ++it) { 125 0 : for (DnsItems::const_iterator item = (*it)->items.begin(); 126 0 : item != (*it)->items.end(); ++item) { 127 : boost::shared_ptr<DnsAgentXmppChannelManager::RecordRequest> 128 : req(new DnsAgentXmppChannelManager::RecordRequest( 129 0 : op, GetDnsRecordName((*it)->virtual_dns, *item), 130 0 : (*it)->virtual_dns, *item)); 131 0 : mgr_->EnqueueRecord(req); 132 0 : } 133 : } 134 0 : } 135 : 136 0 : std::string DnsAgentXmppChannel::GetDnsRecordName(std::string &vdns_name, 137 : const DnsItem &item) { 138 0 : std::stringstream str; 139 0 : str << vdns_name << ":" << item.type << ":" << item.name << ":" << item.data; 140 0 : return str.str(); 141 0 : } 142 : 143 0 : void DnsAgentXmppChannel::GetAgentDnsData(AgentDnsData &data) { 144 0 : data.set_agent(channel_->connection()->endpoint().address().to_string()); 145 0 : std::vector<AgentDnsDataItem> items; 146 0 : for (DataSet::iterator it = update_data_.begin(); 147 0 : it != update_data_.end(); ++it) { 148 0 : AgentDnsDataItem item; 149 0 : item.set_virtual_dns((*it)->virtual_dns); 150 0 : item.set_zone((*it)->zone); 151 0 : std::vector<VirtualDnsRecordTraceData> records; 152 0 : for (DnsItems::iterator iter = (*it)->items.begin(); 153 0 : iter != (*it)->items.end(); ++iter) { 154 0 : VirtualDnsRecordTraceData record; 155 0 : record.rec_name = (*iter).name; 156 0 : record.rec_type = BindUtil::DnsType((*iter).type); 157 0 : record.rec_class = "IN"; 158 0 : record.rec_data = (*iter).data; 159 0 : record.rec_ttl = (*iter).ttl; 160 0 : record.source = "Agent"; 161 0 : record.installed = "yes"; 162 0 : record.rec_source_name = (*iter).source_name; 163 0 : record.rec_vm_uuid = (*iter).vm_uuid; 164 0 : records.push_back(record); 165 0 : } 166 0 : item.set_records(records); 167 0 : items.push_back(item); 168 0 : } 169 0 : data.set_agent_data(items); 170 0 : } 171 : 172 0 : DnsAgentXmppChannelManager::DnsAgentXmppChannelManager( 173 0 : XmppServer *server) 174 0 : : server_(server), 175 0 : work_queue_(TaskScheduler::GetInstance()->GetTaskId("dns::Config"), 0, 176 : boost::bind(&DnsAgentXmppChannelManager::ProcessRecord, 177 0 : this, _1)) { 178 0 : if (server_) { 179 0 : server_->RegisterConnectionEvent(xmps::DNS, 180 : boost::bind(&DnsAgentXmppChannelManager::HandleXmppChannelEvent, 181 : this, _1, _2)); 182 : } 183 0 : } 184 : 185 0 : DnsAgentXmppChannelManager::~DnsAgentXmppChannelManager() { 186 0 : if (server_) 187 0 : server_->UnRegisterConnectionEvent(xmps::DNS); 188 0 : channel_map_.clear(); 189 0 : work_queue_.Shutdown(); 190 0 : } 191 : 192 0 : bool DnsAgentXmppChannelManager::ProcessRecord( 193 : boost::shared_ptr<RecordRequest> req) { 194 0 : Dns::GetDnsManager()->ProcessAgentUpdate(req->op, req->record_name, 195 0 : req->vdns_name, req->item); 196 0 : return true; 197 : } 198 : 199 0 : void DnsAgentXmppChannelManager::EnqueueRecord( 200 : boost::shared_ptr<RecordRequest> req) { 201 0 : work_queue_.Enqueue(req); 202 0 : } 203 : 204 0 : void DnsAgentXmppChannelManager::RemoveChannel(XmppChannel *ch) { 205 0 : channel_map_.erase(ch); 206 0 : } 207 : 208 : DnsAgentXmppChannel * 209 0 : DnsAgentXmppChannelManager::DnsAgentXmppChannelManager::FindChannel( 210 : const XmppChannel *ch) { 211 0 : std::scoped_lock lock(mutex_); 212 0 : ChannelMap::iterator it = channel_map_.find(ch); 213 0 : if (it == channel_map_.end()) 214 0 : return NULL; 215 0 : return it->second; 216 0 : } 217 : 218 : void 219 0 : DnsAgentXmppChannelManager::HandleXmppChannelEvent(XmppChannel *channel, 220 : xmps::PeerState state) { 221 0 : std::scoped_lock lock(mutex_); 222 0 : ChannelMap::iterator it = channel_map_.find(channel); 223 : 224 0 : if (state == xmps::READY) { 225 0 : if (it == channel_map_.end()) { 226 : DnsAgentXmppChannel *agent_xmpp_channel = 227 0 : new DnsAgentXmppChannel(channel, this); 228 0 : channel_map_.insert(std::make_pair(channel, agent_xmpp_channel)); 229 : ConfigClientManager *config_manager = 230 0 : Dns::GetDnsManager()->get_config_manager(); 231 0 : if (config_manager && !config_manager->GetEndOfRibComputed()) { 232 0 : DNS_XMPP_TRACE(DnsXmppTrace, "Peer:" + channel->PeerAddress() + 233 : " Close due to EndofRib not computed"); 234 0 : channel->Close(); 235 : } 236 : } 237 0 : } else if (state == xmps::NOT_READY) { 238 0 : if (it != channel_map_.end()) { 239 0 : DnsAgentXmppChannel *agent_xmpp_channel = (*it).second; 240 0 : agent_xmpp_channel->Close(); 241 0 : delete agent_xmpp_channel; 242 : } else { 243 0 : DNS_XMPP_TRACE(DnsXmppTrace, 244 : "Peer not found on channel not ready event"); 245 : } 246 : } 247 0 : } 248 : 249 0 : uint8_t DnsAgentXmppChannelManager::ChannelToDscp(const XmppChannel *xc) const { 250 0 : const XmppConnection *conn = xc->connection(); 251 0 : if (conn) { 252 0 : const XmppSession *sess = conn->session(); 253 0 : if (sess) { 254 0 : return sess->GetDscpValue(); 255 : } 256 : } 257 0 : return 0; 258 : } 259 : 260 0 : void DnsAgentXmppChannelManager::GetAgentData(std::vector<AgentData> &list) { 261 0 : std::scoped_lock lock(mutex_); 262 0 : for (ChannelMap::iterator iter = channel_map_.begin(); 263 0 : iter != channel_map_.end(); ++iter) { 264 0 : const XmppChannel *channel = iter->first; 265 0 : AgentData agent_data; 266 0 : agent_data.set_peer(channel->ToString()); 267 0 : agent_data.set_peer_address( 268 0 : channel->connection()->endpoint().address().to_string()); 269 0 : agent_data.set_local_address( 270 0 : channel->connection()->local_endpoint().address().to_string()); 271 0 : agent_data.set_state(channel->StateName()); 272 0 : agent_data.set_last_event(channel->LastEvent()); 273 0 : agent_data.set_last_state(channel->LastStateName()); 274 0 : agent_data.set_last_state_at(channel->LastStateChangeAt()); 275 0 : agent_data.set_dscp(ChannelToDscp(channel)); 276 0 : list.push_back(agent_data); 277 0 : } 278 0 : } 279 : 280 0 : void DnsAgentXmppChannelManager::GetAgentDnsData(std::vector<AgentDnsData> &dt) { 281 0 : std::scoped_lock lock(mutex_); 282 0 : for (ChannelMap::iterator iter = channel_map_.begin(); 283 0 : iter != channel_map_.end(); ++iter) { 284 0 : DnsAgentXmppChannel *ch = iter->second; 285 0 : AgentDnsData data; 286 0 : ch->GetAgentDnsData(data); 287 0 : dt.push_back(data); 288 0 : } 289 0 : } 290 : 291 0 : void ShowAgentList::HandleRequest() const { 292 0 : DnsAgentListResponse *resp = new DnsAgentListResponse(); 293 0 : resp->set_context(context()); 294 : 295 0 : std::vector<AgentData> agent_list_sandesh; 296 0 : Dns::GetAgentXmppChannelManager()->GetAgentData(agent_list_sandesh); 297 : 298 0 : resp->set_agent(agent_list_sandesh); 299 0 : resp->Response(); 300 0 : } 301 : 302 0 : void ShowAgentXmppDnsData::HandleRequest() const { 303 0 : AgentXmppDnsDataResponse *resp = new AgentXmppDnsDataResponse(); 304 0 : resp->set_context(context()); 305 : 306 0 : std::vector<AgentDnsData> agent_data; 307 0 : Dns::GetAgentXmppChannelManager()->GetAgentDnsData(agent_data); 308 : 309 0 : resp->set_data(agent_data); 310 0 : resp->Response(); 311 0 : }