Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #include <ctype.h>
6 : #include <stdio.h>
7 : #include <sstream>
8 : #include <fstream>
9 : #include <net/if.h>
10 : #include <boost/uuid/uuid.hpp>
11 : #include <boost/filesystem.hpp>
12 : #include <boost/foreach.hpp>
13 : #include <rapidjson/document.h>
14 : #include <rapidjson/prettywriter.h>
15 : #include <rapidjson/stringbuffer.h>
16 : #include "base/logging.h"
17 : #include "base/task.h"
18 : #include "base/string_util.h"
19 : #include "db/db.h"
20 : #include "db/db_entry.h"
21 : #include "db/db_table.h"
22 : #include "cmn/agent_cmn.h"
23 : #include "init/agent_param.h"
24 : #include "cfg/cfg_init.h"
25 : #include "oper/interface_common.h"
26 : #include "oper/vm.h"
27 : #include "oper/vn.h"
28 : #include "port_ipc/port_ipc_handler.h"
29 : #include "port_ipc/port_ipc_types.h"
30 : #include "port_ipc/port_subscribe_table.h"
31 :
32 : using boost::uuids::nil_uuid;
33 : namespace fs = boost::filesystem;
34 :
35 : /////////////////////////////////////////////////////////////////////////////
36 : // Utility methods
37 : /////////////////////////////////////////////////////////////////////////////
38 825 : static bool GetStringMember(const contrail_rapidjson::Value &d, const char *member,
39 : std::string *data, std::string *err) {
40 825 : if (!d.HasMember(member) || !d[member].IsString()) {
41 0 : if (err) {
42 0 : *err += "Invalid or missing field for <" + string(member) + ">";
43 : }
44 0 : return false;
45 : }
46 :
47 825 : *data = d[member].GetString();
48 825 : return true;
49 : }
50 :
51 825 : static bool GetUint32Member(const contrail_rapidjson::Value &d, const char *member,
52 : uint32_t *data, std::string *err) {
53 825 : if (!d.HasMember(member) || !d[member].IsInt()) {
54 165 : if (err) {
55 0 : *err += "Invalid or missing field for <" + string(member) + ">";
56 : }
57 165 : return false;
58 : }
59 :
60 660 : *data = d[member].GetInt();
61 660 : return true;
62 : }
63 :
64 660 : static bool GetUuidMember(const contrail_rapidjson::Value &d, const char *member,
65 : boost::uuids::uuid *u, std::string *err) {
66 660 : if (!d.HasMember(member) || !d[member].IsString()) {
67 0 : if (err) {
68 0 : *err += "Invalid or missing data for <" + string(member) + ">";
69 : }
70 0 : return false;
71 : }
72 :
73 660 : *u = StringToUuid(d[member].GetString());
74 660 : return true;
75 : }
76 :
77 0 : static void InterfaceResync(Agent *agent, const boost::uuids::uuid &u,
78 : const string &name, bool link_status) {
79 0 : InterfaceTable *table = agent->interface_table();
80 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
81 0 : req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, u, name));
82 0 : req.data.reset(new VmInterfaceOsOperStateData(link_status));
83 0 : table->Enqueue(&req);
84 0 : }
85 :
86 : /////////////////////////////////////////////////////////////////////////////
87 : // PortIpcHandler methods
88 : /////////////////////////////////////////////////////////////////////////////
89 2 : PortIpcHandler::PortIpcHandler(Agent *agent, const std::string &dir)
90 2 : : agent_(agent), ports_dir_(dir), vmvn_dir_(dir + "/vm"), version_(0),
91 2 : interface_stale_cleaner_(new InterfaceConfigStaleCleaner(agent)),
92 4 : port_subscribe_table_(new PortSubscribeTable(agent_)) {
93 2 : interface_stale_cleaner_->set_callback(
94 : boost::bind(&InterfaceConfigStaleCleaner::OnInterfaceConfigStaleTimeout,
95 : interface_stale_cleaner_.get(), _1));
96 2 : uint32_t timeout_secs = agent->params()->stale_interface_cleanup_timeout();
97 : //Set timeout in milliseconds
98 2 : interface_stale_cleaner_->set_timeout(timeout_secs * 1000);
99 :
100 2 : fs::path ports_dir(ports_dir_);
101 2 : if (fs::exists(ports_dir) == false) {
102 0 : if (!fs::create_directories(ports_dir)) {
103 0 : string err_msg = "Creating directory " + ports_dir_ + " failed";
104 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
105 0 : }
106 : }
107 :
108 : // Create directory for vm-vn subscription config files
109 2 : fs::path vmvn_dir(vmvn_dir_);
110 2 : if (fs::exists(vmvn_dir) == false) {
111 0 : if (!fs::create_directories(vmvn_dir)) {
112 0 : string err_msg = "Creating directory " + vmvn_dir_ + " failed";
113 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
114 0 : }
115 : }
116 2 : }
117 :
118 4 : PortIpcHandler::~PortIpcHandler() {
119 4 : }
120 :
121 0 : void PortIpcHandler::ReloadAllPorts(const std::string &dir, bool check_port,
122 : bool vm_vn_ports) {
123 0 : fs::path ports_dir(dir);
124 0 : fs::directory_iterator end_iter;
125 :
126 0 : if (!fs::exists(ports_dir) || !fs::is_directory(ports_dir)) {
127 0 : return;
128 : }
129 :
130 0 : fs::directory_iterator it(ports_dir);
131 0 : BOOST_FOREACH(fs::path const &p, std::make_pair(it, end_iter)) {
132 0 : if (!fs::is_regular_file(p)) {
133 0 : continue;
134 : }
135 : /* Skip if filename is not in UUID format */
136 0 : if (!IsUUID(p.filename().string())) {
137 0 : continue;
138 : }
139 :
140 0 : ProcessFile(p.string(), check_port, vm_vn_ports);
141 0 : }
142 0 : }
143 :
144 0 : void PortIpcHandler::ReloadAllPorts(bool check_port) {
145 0 : ReloadAllPorts(ports_dir_, check_port, false);
146 :
147 : /* Process each vm directory under vmvn_dir_ */
148 0 : fs::path vmvn_dir(vmvn_dir_);
149 0 : fs::directory_iterator end_iter;
150 :
151 0 : if (!fs::exists(vmvn_dir) || !fs::is_directory(vmvn_dir)) {
152 0 : return;
153 : }
154 0 : fs::directory_iterator it(vmvn_dir);
155 0 : BOOST_FOREACH(fs::path const &p, std::make_pair(it, end_iter)) {
156 0 : if (!fs::is_directory(p)) {
157 0 : continue;
158 : }
159 0 : ReloadAllPorts(p.string(), check_port, true);
160 0 : }
161 0 : }
162 :
163 0 : void PortIpcHandler::ProcessFile(const string &file, bool check_port,
164 : bool vm_vn_ports) {
165 0 : string err_msg;
166 0 : std::ifstream f(file.c_str());
167 0 : if (!f.good()) {
168 0 : return;
169 : }
170 0 : std::ostringstream tmp;
171 0 : tmp<<f.rdbuf();
172 0 : string json = tmp.str();
173 0 : f.close();
174 :
175 0 : if (vm_vn_ports == false)
176 0 : AddPortFromJson(json, check_port, err_msg, false);
177 : else
178 0 : AddVmVnPort(json, check_port, err_msg, false);
179 0 : }
180 :
181 0 : bool PortIpcHandler::AddPortArrayFromJson(const contrail_rapidjson::Value &d,
182 : const string &json,
183 : VmiSubscribeEntryPtrList &req_list,
184 : bool check_port,
185 : string &err_msg) {
186 0 : for (size_t i = 0; i < d.Size(); i++) {
187 0 : const contrail_rapidjson::Value& elem = d[i];
188 0 : if (elem.IsObject() == false) {
189 0 : err_msg = "Json Array has invalid element ==> " + json;
190 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
191 0 : return false;
192 : }
193 :
194 : PortSubscribeEntry *entry =
195 0 : MakeAddVmiUuidRequest(elem, check_port, err_msg);
196 0 : if (entry == NULL) {
197 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
198 0 : return false;
199 : }
200 :
201 0 : req_list.push_back(PortSubscribeEntryPtr(entry));
202 : }
203 0 : return true;
204 : }
205 :
206 165 : bool PortIpcHandler::AddPortFromJson(const string &json, bool check_port,
207 : string &err_msg, bool write_file) {
208 165 : contrail_rapidjson::Document d;
209 165 : if (d.Parse<0>(const_cast<char *>(json.c_str())).HasParseError()) {
210 0 : err_msg = "Invalid Json string ==> " + json;
211 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
212 0 : return false;
213 : }
214 165 : if (!d.IsObject() && !d.IsArray()) {
215 0 : err_msg = "Unexpected Json string ==> " + json;
216 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
217 0 : return false;
218 : }
219 :
220 165 : if (d.IsArray()) {
221 : /* When Json Array is passed, we do 'All or None'. We add all the
222 : * elements of the array or none are added. So we do validation in
223 : * first pass and addition in second pass */
224 0 : VmiSubscribeEntryPtrList req_list;
225 0 : if (AddPortArrayFromJson(d, json, req_list, check_port, err_msg)) {
226 0 : for (size_t i = 0; i < req_list.size(); i++) {
227 0 : AddVmiUuidEntry(req_list[i], d, write_file, err_msg);
228 : }
229 : }
230 :
231 0 : req_list.clear();
232 0 : return true;
233 0 : }
234 :
235 165 : PortSubscribeEntryPtr entry(MakeAddVmiUuidRequest(d, check_port, err_msg));
236 165 : if (entry.get() == NULL) {
237 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
238 0 : return false;
239 : }
240 :
241 165 : AddVmiUuidEntry(entry, d, write_file, err_msg);
242 165 : return true;
243 165 : }
244 :
245 165 : VmiSubscribeEntry *PortIpcHandler::MakeAddVmiUuidRequest
246 : (const contrail_rapidjson::Value &d, bool check_port,
247 : std::string &err_msg) const {
248 : boost::uuids::uuid vmi_uuid;
249 165 : if (GetUuidMember(d, "id", &vmi_uuid, &err_msg) == false) {
250 0 : return NULL;
251 : }
252 :
253 : boost::uuids::uuid instance_uuid;
254 165 : if (GetUuidMember(d, "instance-id", &instance_uuid, &err_msg) == false) {
255 0 : return NULL;
256 : }
257 :
258 : boost::uuids::uuid vn_uuid;
259 165 : if (GetUuidMember(d, "vn-id", &vn_uuid, &err_msg) == false) {
260 0 : return NULL;
261 : }
262 :
263 : boost::uuids::uuid project_uuid;
264 165 : if (GetUuidMember(d, "vm-project-id", &project_uuid, &err_msg) == false) {
265 0 : return NULL;
266 : }
267 :
268 165 : string vm_name;
269 165 : if (GetStringMember(d, "display-name", &vm_name, &err_msg) == false) {
270 0 : return NULL;
271 : }
272 :
273 165 : string ip4_str;
274 165 : if (GetStringMember(d, "ip-address", &ip4_str, &err_msg) == false) {
275 0 : return NULL;
276 : }
277 165 : boost::system::error_code ec;
278 165 : Ip4Address ip4 = Ip4Address::from_string(ip4_str, ec);
279 :
280 165 : string ip6_str;
281 165 : if (GetStringMember(d, "ip6-address", &ip6_str, &err_msg) == false) {
282 0 : return NULL;
283 : }
284 165 : boost::system::error_code ec6;
285 165 : Ip6Address ip6 = Ip6Address::from_string(ip6_str, ec6);
286 :
287 : uint32_t val;
288 165 : if (GetUint32Member(d, "type", &val, &err_msg) == false) {
289 0 : return NULL;
290 : }
291 :
292 165 : PortSubscribeEntry::Type vmi_type = PortSubscribeEntry::VMPORT;
293 165 : uint32_t link_state = 1;
294 165 : if (val == 1) {
295 0 : vmi_type = PortSubscribeEntry::NAMESPACE;
296 165 : } else if (val == 2) {
297 0 : vmi_type = PortSubscribeEntry::REMOTE_PORT;
298 : /* Default port-state is disabled for REMOTE_PORT */
299 0 : link_state = 0;
300 : }
301 165 : if (vmi_type == PortSubscribeEntry::VMPORT) {
302 165 : if (vn_uuid == nil_uuid()) {
303 0 : err_msg = "Invalid VN uuid";
304 0 : return NULL;
305 : }
306 : }
307 :
308 165 : string ifname;
309 165 : if (GetStringMember(d, "system-name", &ifname, &err_msg) == false) {
310 0 : return NULL;
311 : }
312 : // Verify that interface exists in OS
313 165 : if (vmi_type != PortSubscribeEntry::REMOTE_PORT) {
314 165 : if (check_port && !InterfaceExists(ifname)) {
315 0 : err_msg = "Interface does not exist in OS";
316 0 : return NULL;
317 : }
318 : }
319 :
320 165 : string mac;
321 165 : if (GetStringMember(d, "mac-address", &mac, &err_msg) == false) {
322 0 : return NULL;
323 : }
324 165 : if (ValidateMac(mac) == false) {
325 0 : err_msg = "Invalid MAC, Use xx:xx:xx:xx:xx:xx format";
326 0 : return NULL;
327 : }
328 :
329 : // Sanity check. We should not have isolated_vlan_id set and vlan_id unset
330 165 : uint32_t rx_vlan_id = VmInterface::kInvalidVlanId;
331 165 : if (GetUint32Member(d, "rx-vlan-id", &rx_vlan_id, &err_msg) == false) {
332 0 : return NULL;
333 : }
334 :
335 165 : uint32_t tx_vlan_id = VmInterface::kInvalidVlanId;
336 165 : if (GetUint32Member(d, "tx-vlan-id", &tx_vlan_id, &err_msg) == false) {
337 0 : return NULL;
338 : }
339 :
340 165 : if ((rx_vlan_id != VmInterface::kInvalidVlanId) &&
341 0 : (tx_vlan_id == VmInterface::kInvalidVlanId-1)) {
342 : err_msg += "Invalid request. RX (isolated) vlan set, "
343 0 : "but TX vlan not set";
344 0 : return NULL;
345 : }
346 :
347 : // Dont return in case of error as this is an optional parameter for
348 : // DPDK/vhostuser
349 165 : uint32_t vhostuser_mode = 0;
350 165 : GetUint32Member(d, "vhostuser-mode", &vhostuser_mode, &err_msg);
351 : /* Don't return error in case link-state is not found. This is required
352 : * for backward compatibility when old files are used with new
353 : * vrouter-agent. If field is absent then value as initialized above
354 : * for link_state gets used */
355 165 : GetUint32Member(d, "link-state", &link_state, NULL);
356 :
357 165 : CONFIG_TRACE(AddPortEnqueue, "Add", UuidToString(vmi_uuid),
358 : UuidToString(instance_uuid), UuidToString(vn_uuid),
359 : ip4.to_string(), ifname, mac, vm_name, tx_vlan_id, rx_vlan_id,
360 : UuidToString(project_uuid),
361 : PortSubscribeEntry::TypeToString(vmi_type),
362 : ip6.to_string(), version_, vhostuser_mode, link_state);
363 165 : return new VmiSubscribeEntry(vmi_type, ifname, version_, vmi_uuid,
364 : instance_uuid, vm_name, vn_uuid, project_uuid,
365 : ip4, ip6, mac, tx_vlan_id, rx_vlan_id,
366 165 : vhostuser_mode, link_state);
367 165 : }
368 :
369 165 : bool PortIpcHandler::AddVmiUuidEntry(PortSubscribeEntryPtr entry_ref,
370 : const contrail_rapidjson::Value &d,
371 : bool write_file, string &err_msg) const {
372 : VmiSubscribeEntry *entry =
373 165 : dynamic_cast<VmiSubscribeEntry *>(entry_ref.get());
374 : // If Writing to file fails return error
375 165 : if(write_file && WriteJsonToFile(entry, false) == false) {
376 0 : err_msg += "Writing of Json string to file failed for " +
377 0 : UuidToString(entry->vmi_uuid());
378 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
379 0 : return false;
380 : }
381 :
382 165 : CONFIG_TRACE(AddPortEnqueue, "Add", UuidToString(entry->vmi_uuid()),
383 : UuidToString(entry->vm_uuid()), UuidToString(entry->vn_uuid()),
384 : entry->ip4_addr().to_string(), entry->ifname(),
385 : entry->mac_addr(), entry->vm_name(), entry->tx_vlan_id(),
386 : entry->rx_vlan_id(), UuidToString(entry->project_uuid()),
387 : PortSubscribeEntry::TypeToString(entry->type()),
388 : entry->ip6_addr().to_string(), entry->version(),
389 : entry->vhostuser_mode(), entry->link_state());
390 165 : port_subscribe_table_->AddVmi(entry->vmi_uuid(), entry_ref);
391 165 : return true;
392 : }
393 :
394 0 : bool PortIpcHandler::WriteJsonToFile(VmiSubscribeEntry *entry, bool overwrite)
395 : const {
396 0 : string filename = ports_dir_ + "/" + UuidToString(entry->vmi_uuid());
397 0 : fs::path file_path(filename);
398 :
399 0 : bool remove = true;
400 : /* Don't overwrite if the file already exists */
401 0 : if (!overwrite) {
402 0 : remove = !fs::exists(file_path);
403 0 : if (!remove) {
404 0 : return true;
405 : }
406 : }
407 :
408 0 : string info = MakeVmiUuidJson(entry, true);
409 0 : if (info.empty()) {
410 0 : LOG(ERROR, "Error producing entry JSON for port " << file_path.filename());
411 0 : return false;
412 : }
413 0 : std::ofstream fs(filename.c_str());
414 0 : if (fs.fail()) {
415 0 : LOG(ERROR, "Cannot open file " << filename << " for writing");
416 0 : return false;
417 : }
418 0 : bool output = (fs << info).good();
419 0 : fs.close();
420 0 : if (!output) {
421 0 : LOG(ERROR, "Cannot write JSON to the file " << filename);
422 0 : if (remove) {
423 0 : fs::remove(file_path);
424 : }
425 : }
426 :
427 0 : return output;
428 0 : }
429 :
430 165 : bool PortIpcHandler::ValidateMac(const string &mac) const {
431 165 : size_t pos = 0;
432 165 : int colon = 0;
433 165 : if (mac.empty()) {
434 0 : return false;
435 : }
436 990 : while ((pos = mac.find(':', pos)) != std::string::npos) {
437 825 : colon++;
438 825 : pos += 1;
439 : }
440 165 : if (colon != 5)
441 0 : return false;
442 :
443 165 : if (MacAddress::FromString(mac).IsZero())
444 0 : return false;
445 :
446 165 : return true;
447 : }
448 :
449 0 : bool PortIpcHandler::DeletePort(const string &url, string &err_msg) {
450 0 : boost::uuids::uuid vmi_uuid = StringToUuid(url);
451 0 : if (vmi_uuid != nil_uuid()) {
452 0 : DeleteVmiUuidEntry(vmi_uuid, err_msg);
453 0 : return true;
454 : }
455 :
456 0 : return true;
457 : }
458 :
459 186 : void PortIpcHandler::DeleteVmiUuidEntry(
460 : const boost::uuids::uuid &u, string &err_msg) {
461 186 : uint64_t version = 0;
462 186 : PortSubscribeEntryPtr entry = port_subscribe_table_->GetVmi(u);
463 186 : if (entry.get() != NULL) {
464 165 : version = entry->version();
465 : }
466 186 : port_subscribe_table_->DeleteVmi(u);
467 186 : CONFIG_TRACE(DeletePortEnqueue, "Delete", UuidToString(u), version);
468 :
469 372 : string file = ports_dir_ + "/" + UuidToString(u);
470 186 : fs::path file_path(file);
471 :
472 186 : if (fs::exists(file_path) && fs::is_regular_file(file_path)) {
473 0 : if (remove(file.c_str())) {
474 0 : err_msg = "Error deleting file " + file;
475 : }
476 : }
477 186 : }
478 :
479 0 : bool PortIpcHandler::EnablePort(const string &url, string &err_msg) {
480 0 : boost::uuids::uuid u = StringToUuid(url);
481 0 : if (u == nil_uuid()) {
482 0 : err_msg = "Port Not found " + url;
483 0 : return false;
484 : }
485 0 : PortSubscribeEntryPtr entry = port_subscribe_table_->GetVmi(u);
486 0 : if (entry.get() == NULL) {
487 0 : err_msg = "Port Not found " + url;
488 0 : return false;
489 : }
490 0 : if (entry->type() != PortSubscribeEntry::REMOTE_PORT) {
491 0 : err_msg = "Incorrect Port type for " + url;
492 0 : return false;
493 : }
494 : VmiSubscribeEntry *ventry =
495 0 : dynamic_cast<VmiSubscribeEntry *>(entry.get());
496 0 : if (ventry == NULL) {
497 0 : err_msg = "Invalid Port " + url;
498 0 : return false;
499 : }
500 0 : int written_to_file = 0;
501 0 : if (!ventry->link_state()) {
502 0 : ventry->set_link_state(1);
503 0 : written_to_file = 1;
504 0 : if (WriteJsonToFile(ventry, true) == false) {
505 0 : err_msg += "Writing of Json to file failed on enable for " +
506 0 : UuidToString(ventry->vmi_uuid());
507 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
508 0 : written_to_file = 0;
509 : }
510 : }
511 0 : InterfaceResync(agent_, u, entry->ifname(), true);
512 0 : string msg = "Enable state for " + url + " version " +
513 0 : integerToString(entry->version()) + " written to file : " +
514 0 : integerToString(written_to_file);
515 0 : CONFIG_TRACE(PortInfo, msg);
516 0 : return true;
517 0 : }
518 :
519 0 : bool PortIpcHandler::DisablePort(const string &url, string &err_msg) {
520 0 : boost::uuids::uuid u = StringToUuid(url);
521 0 : if (u == nil_uuid()) {
522 0 : err_msg = "Port Not found " + url;
523 0 : return false;
524 : }
525 0 : PortSubscribeEntryPtr entry = port_subscribe_table_->GetVmi(u);
526 0 : if (entry.get() == NULL) {
527 0 : err_msg = "Port Not found " + url;
528 0 : return false;
529 : }
530 0 : if (entry->type() != PortSubscribeEntry::REMOTE_PORT) {
531 0 : err_msg = "Incorrect Port type for " + url;
532 0 : return false;
533 : }
534 : VmiSubscribeEntry *ventry =
535 0 : dynamic_cast<VmiSubscribeEntry *>(entry.get());
536 0 : if (ventry == NULL) {
537 0 : err_msg = "Invalid Port " + url;
538 0 : return false;
539 : }
540 0 : int written_to_file = 0;
541 0 : if (ventry->link_state()) {
542 0 : ventry->set_link_state(0);
543 0 : written_to_file = 1;
544 0 : if (WriteJsonToFile(ventry, true) == false) {
545 0 : err_msg += "Writing of Json to file failed on disable for " +
546 0 : UuidToString(ventry->vmi_uuid());
547 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
548 0 : written_to_file = 0;
549 : }
550 : }
551 0 : InterfaceResync(agent_, u, entry->ifname(), false);
552 0 : string msg = "Disable state for " + url + " version " +
553 0 : integerToString(entry->version()) + " written to file : " +
554 0 : integerToString(written_to_file);
555 0 : CONFIG_TRACE(PortInfo, msg);
556 0 : return true;
557 0 : }
558 :
559 0 : bool PortIpcHandler::IsUUID(const string &uuid_str) const {
560 0 : boost::uuids::uuid vmi_uuid = StringToUuid(uuid_str);
561 0 : if (vmi_uuid == nil_uuid()) {
562 0 : return false;
563 : }
564 0 : return true;
565 : }
566 :
567 1485 : void PortIpcHandler::AddMember(const char *key, const char *value,
568 : contrail_rapidjson::Document *doc) const {
569 1485 : contrail_rapidjson::Document::AllocatorType &a = doc->GetAllocator();
570 1485 : contrail_rapidjson::Value v;
571 1485 : contrail_rapidjson::Value vk;
572 1485 : doc->AddMember(vk.SetString(key, a), v.SetString(value, a), a);
573 1485 : }
574 :
575 165 : std::string PortIpcHandler::MakeVmiUuidJson(const VmiSubscribeEntry *entry,
576 : bool meta_info) const {
577 165 : contrail_rapidjson::Document doc;
578 165 : doc.SetObject();
579 165 : contrail_rapidjson::Document::AllocatorType &a = doc.GetAllocator();
580 :
581 165 : string str1 = UuidToString(entry->vmi_uuid());
582 165 : AddMember("id", str1.c_str(), &doc);
583 165 : string str2 = UuidToString(entry->vm_uuid());
584 165 : AddMember("instance-id", str2.c_str(), &doc);
585 165 : AddMember("display-name", entry->vm_name().c_str(), &doc);
586 165 : string str3 = entry->ip4_addr().to_string();
587 165 : AddMember("ip-address", str3.c_str(), &doc);
588 165 : string str4 = entry->ip6_addr().to_string();
589 165 : AddMember("ip6-address", str4.c_str(), &doc);
590 165 : string str5 = UuidToString(entry->vn_uuid());
591 165 : AddMember("vn-id", str5.c_str(), &doc);
592 165 : string str6 = UuidToString(entry->project_uuid());
593 165 : AddMember("vm-project-id", str6.c_str(), &doc);
594 165 : AddMember("mac-address", entry->mac_addr().c_str(), &doc);
595 165 : AddMember("system-name", entry->ifname().c_str(), &doc);
596 165 : doc.AddMember("type", (int)entry->type(), a);
597 165 : doc.AddMember("rx-vlan-id", (int)entry->rx_vlan_id(), a);
598 165 : doc.AddMember("tx-vlan-id", (int)entry->tx_vlan_id(), a);
599 165 : doc.AddMember("vhostuser-mode", (int)entry->vhostuser_mode(), a);
600 : /* link-state has to be persisted for port-type of REMOTE_PORT.
601 : * REMOTE_PORT will NOT have corresponding tap interface in OS to pick
602 : * operational state. */
603 165 : if (entry->type() == PortSubscribeEntry::REMOTE_PORT) {
604 0 : doc.AddMember("link-state", (int)entry->link_state(), a);
605 : }
606 165 : if (meta_info) {
607 0 : AddMember("author", agent_->program_name().c_str(), &doc);
608 0 : string now = duration_usecs_to_string(UTCTimestampUsec());
609 0 : AddMember("time", now.c_str(), &doc);
610 0 : }
611 :
612 165 : contrail_rapidjson::StringBuffer buffer;
613 165 : contrail_rapidjson::PrettyWriter<contrail_rapidjson::StringBuffer> writer(buffer);
614 165 : doc.Accept(writer);
615 :
616 330 : return buffer.GetString();
617 165 : }
618 :
619 0 : bool PortIpcHandler::GetPortInfo(const string &uuid_str, string &info) const {
620 0 : boost::uuids::uuid vmi_uuid = StringToUuid(uuid_str);
621 0 : if (vmi_uuid == nil_uuid()) {
622 0 : return false;
623 : }
624 :
625 0 : return MakeJsonFromVmi(vmi_uuid, info);
626 : }
627 :
628 0 : void PortIpcHandler::SyncHandler() {
629 0 : ++version_;
630 0 : interface_stale_cleaner_->StartStaleCleanTimer(version_);
631 0 : string msg = " Sync " + integerToString(version_);
632 0 : CONFIG_TRACE(PortInfo, msg);
633 0 : }
634 :
635 2 : void PortIpcHandler::InitDone() {
636 2 : port_subscribe_table_->InitDone();
637 2 : }
638 :
639 2 : void PortIpcHandler::Shutdown() {
640 2 : port_subscribe_table_->Shutdown();
641 2 : }
642 :
643 0 : bool PortIpcHandler::BuildGatewayArrayElement
644 : (const contrail_rapidjson::Value &d, VirtualGatewayConfig::Subnet *entry) const {
645 0 : if (!d.HasMember("ip-address") || !d["ip-address"].IsString()) {
646 0 : return false;
647 : }
648 :
649 0 : if (!d.HasMember("prefix-len") || !d["prefix-len"].IsInt()) {
650 0 : return false;
651 : }
652 0 : boost::system::error_code ec;
653 0 : entry->ip_ = Ip4Address::from_string(d["ip-address"].GetString(), ec);
654 0 : if (ec.failed()) {
655 0 : return false;
656 : }
657 0 : entry->plen_ = d["prefix-len"].GetInt();
658 0 : return true;
659 : }
660 :
661 0 : bool PortIpcHandler::ValidGatewayJsonString
662 : (const contrail_rapidjson::Value &d, VirtualGatewayConfig::SubnetList *list) const {
663 0 : for (size_t i = 0; i < d.Size(); i++) {
664 0 : const contrail_rapidjson::Value& elem = d[i];
665 0 : if (!elem.IsObject()) {
666 0 : return false;
667 : }
668 0 : VirtualGatewayConfig::Subnet entry;
669 0 : if (!BuildGatewayArrayElement(elem, &entry)) {
670 0 : return false;
671 : }
672 0 : list->push_back(entry);
673 0 : }
674 0 : return true;
675 : }
676 :
677 0 : bool PortIpcHandler::HasAllGatewayFields(const contrail_rapidjson::Value &d,
678 : std::string &member_err,
679 : VirtualGatewayInfo *req) const {
680 0 : if (!d.HasMember("interface") || !d["interface"].IsString()) {
681 0 : member_err = "interface";
682 0 : return false;
683 : }
684 :
685 0 : if (!d.HasMember("routing-instance") || !d["routing-instance"].IsString()) {
686 0 : member_err = "routing-instance";
687 0 : return false;
688 : }
689 :
690 0 : if (!d.HasMember("subnets") || !d["subnets"].IsArray()) {
691 0 : member_err = "subnets";
692 0 : return false;
693 : }
694 :
695 0 : if (!ValidGatewayJsonString(d["subnets"], &req->subnets_)) {
696 0 : member_err = "subnets value";
697 0 : return false;
698 : }
699 :
700 0 : if (!d.HasMember("routes") || !d["routes"].IsArray()) {
701 0 : member_err = "routes";
702 0 : return false;
703 : }
704 :
705 0 : if (!ValidGatewayJsonString(d["routes"], &req->routes_)) {
706 0 : member_err = "routes value";
707 0 : return false;
708 : }
709 0 : req->interface_name_ = d["interface"].GetString();
710 0 : req->vrf_name_ = d["routing-instance"].GetString();
711 :
712 0 : return true;
713 : }
714 :
715 0 : bool PortIpcHandler::BuildGateway(const contrail_rapidjson::Value &d,
716 : const string &json, string &err_msg,
717 : VirtualGatewayInfo *req) const {
718 0 : string member_err;
719 0 : if (!HasAllGatewayFields(d, member_err, req)) {
720 : err_msg = "Json string does not have all required members, "
721 0 : + member_err + " is missing ==> "
722 0 : + json;
723 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
724 0 : return false;
725 : }
726 0 : return true;
727 0 : }
728 :
729 0 : bool PortIpcHandler::AddVgwFromJson(const string &json, string &err_msg) const {
730 0 : contrail_rapidjson::Document d;
731 0 : if (d.Parse<0>(const_cast<char *>(json.c_str())).HasParseError()) {
732 0 : err_msg = "Invalid Json string ==> " + json;
733 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
734 0 : return false;
735 : }
736 0 : if (!d.IsArray()) {
737 0 : err_msg = "Unexpected Json string (not an array) ==> " + json;
738 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
739 0 : return false;
740 : }
741 :
742 0 : std::vector<VirtualGatewayInfo> req_list;
743 0 : for (size_t i = 0; i < d.Size(); i++) {
744 0 : const contrail_rapidjson::Value& elem = d[i];
745 0 : if (elem.IsObject()) {
746 0 : VirtualGatewayInfo req("");
747 0 : if (!BuildGateway(elem, json, err_msg, &req)) {
748 0 : return false;
749 : }
750 0 : req_list.push_back(req);
751 0 : } else {
752 0 : err_msg = "Json Array has invalid element ==> " + json;
753 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
754 0 : return false;
755 : }
756 : }
757 :
758 0 : if (!req_list.empty()) {
759 : boost::shared_ptr<VirtualGatewayData>
760 : vgw_data(new VirtualGatewayData(VirtualGatewayData::Add, req_list,
761 0 : 0));
762 0 : agent_->params()->vgw_config_table()->Enqueue(vgw_data);
763 0 : CONFIG_TRACE(VgwEnqueue, "Add", json);
764 0 : }
765 0 : return true;
766 0 : }
767 :
768 0 : bool PortIpcHandler::DelVgwFromJson(const string &json, string &err_msg) const {
769 0 : contrail_rapidjson::Document d;
770 0 : if (d.Parse<0>(const_cast<char *>(json.c_str())).HasParseError()) {
771 0 : err_msg = "Invalid Json string ==> " + json;
772 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
773 0 : return false;
774 : }
775 0 : if (!d.IsArray()) {
776 0 : err_msg = "Unexpected Json string (not an array) ==> " + json;
777 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
778 0 : return false;
779 : }
780 :
781 0 : std::vector<VirtualGatewayInfo> req_list;
782 0 : for (size_t i = 0; i < d.Size(); i++) {
783 0 : const contrail_rapidjson::Value& elem = d[i];
784 0 : if (elem.IsObject()) {
785 0 : if (!elem.HasMember("interface") || !elem["interface"].IsString()) {
786 : err_msg = "Json string does not have or has invalid value for "
787 0 : "member interface ==> " + json;
788 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
789 0 : return false;
790 : }
791 0 : VirtualGatewayInfo req(elem["interface"].GetString());
792 0 : req_list.push_back(req);
793 0 : } else {
794 0 : err_msg = "Json Array has invalid element ==> " + json;
795 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
796 0 : return false;
797 : }
798 : }
799 :
800 0 : if (!req_list.empty()) {
801 : boost::shared_ptr<VirtualGatewayData>
802 : vgw_data(new VirtualGatewayData(VirtualGatewayData::Delete,
803 0 : req_list, 0));
804 0 : agent_->params()->vgw_config_table()->Enqueue(vgw_data);
805 0 : CONFIG_TRACE(VgwEnqueue, "Del", json);
806 0 : }
807 0 : return true;
808 0 : }
809 :
810 : /////////////////////////////////////////////////////////////////////////////
811 : // VM based message related methods
812 : /////////////////////////////////////////////////////////////////////////////
813 0 : bool PortIpcHandler::AddVmVnPort(const string &json, bool check_port,
814 : string &err_msg, bool write_file) {
815 0 : contrail_rapidjson::Document d;
816 0 : if (d.Parse<0>(const_cast<char *>(json.c_str())).HasParseError()) {
817 0 : err_msg = "Invalid Json string ==> " + json;
818 0 : CONFIG_TRACE(VmVnPortInfo, err_msg.c_str());
819 0 : return false;
820 : }
821 :
822 0 : if (!d.IsObject()) {
823 0 : err_msg = "Unexpected Json string ==> " + json;
824 0 : CONFIG_TRACE(VmVnPortInfo, err_msg.c_str());
825 0 : return false;
826 : }
827 :
828 0 : if (d.IsArray()) {
829 0 : err_msg = "Arrays not supported in json for vm ==> " + json;
830 0 : CONFIG_TRACE(VmVnPortInfo, err_msg.c_str());
831 0 : return false;
832 : }
833 :
834 0 : PortSubscribeEntryPtr entry(MakeAddVmVnPortRequest(d, check_port, err_msg));
835 0 : if (entry.get() == NULL) {
836 0 : CONFIG_TRACE(VmVnPortInfo, err_msg.c_str());
837 0 : return false;
838 : }
839 :
840 0 : AddVmVnPortEntry(entry, d, write_file, err_msg);
841 0 : return true;
842 0 : }
843 :
844 0 : bool PortIpcHandler::AddVmVnPortEntry(PortSubscribeEntryPtr entry_ref,
845 : const contrail_rapidjson::Value &d,
846 : bool write_file, string &err_msg) const {
847 : VmVnPortSubscribeEntry *entry =
848 0 : dynamic_cast<VmVnPortSubscribeEntry *>(entry_ref.get());
849 : // If Writing to file fails return error
850 0 : if(write_file && WriteJsonToFile(entry) == false) {
851 0 : err_msg += "Writing of Json string to file failed for Vm " +
852 0 : UuidToString(entry->vm_uuid());
853 0 : CONFIG_TRACE(VmVnPortInfo, err_msg.c_str());
854 0 : return false;
855 : }
856 :
857 0 : CONFIG_TRACE(AddVmVnPortEnqueue, "Add", UuidToString(entry->vm_uuid()),
858 : UuidToString(entry->vn_uuid()), UuidToString(entry->vmi_uuid()),
859 : entry->vm_name(), entry->vm_identifier(), entry->ifname(),
860 : entry->vm_ifname(), entry->vm_namespace(), version_);
861 0 : port_subscribe_table_->AddVmVnPort(entry->vm_uuid(),
862 0 : entry->vn_uuid(), entry->vmi_uuid(), entry_ref);
863 0 : return true;
864 : }
865 :
866 0 : VmVnPortSubscribeEntry *PortIpcHandler::MakeAddVmVnPortRequest
867 : (const contrail_rapidjson::Value &d, bool check_port,
868 : std::string &err_msg) const {
869 0 : PortSubscribeEntry::Type vmi_type = PortSubscribeEntry::VMPORT;
870 : boost::uuids::uuid vm_uuid;
871 0 : if (GetUuidMember(d, "vm-uuid", &vm_uuid, &err_msg) == false) {
872 0 : return NULL;
873 : }
874 :
875 0 : string host_ifname;
876 0 : if (GetStringMember(d, "host-ifname", &host_ifname, &err_msg) == false) {
877 0 : return NULL;
878 : }
879 : // Verify that interface exists in OS
880 0 : if (vmi_type != PortSubscribeEntry::REMOTE_PORT) {
881 0 : if (check_port && !InterfaceExists(host_ifname)) {
882 0 : err_msg = "Interface does not exist in OS";
883 0 : return NULL;
884 : }
885 : }
886 :
887 0 : string vm_name;
888 0 : if (GetStringMember(d, "vm-name", &vm_name, &err_msg) == false) {
889 0 : return NULL;
890 : }
891 :
892 0 : string vm_identifier;
893 0 : GetStringMember(d, "vm-id", &vm_identifier, NULL);
894 :
895 0 : string vm_ifname;
896 0 : GetStringMember(d, "vm-ifname", &vm_ifname, NULL);
897 :
898 0 : string vm_namespace;
899 0 : GetStringMember(d, "vm-namespace", &vm_namespace, NULL);
900 :
901 : boost::uuids::uuid vn_uuid;
902 0 : if (GetUuidMember(d, "vn-uuid", &vn_uuid, &err_msg) == false) {
903 0 : return NULL;
904 : }
905 :
906 : boost::uuids::uuid vmi_uuid;
907 0 : if (GetUuidMember(d, "vmi-uuid", &vmi_uuid, &err_msg) == false) {
908 0 : return NULL;
909 : }
910 :
911 0 : CONFIG_TRACE(AddVmVnPortEnqueue, "Add", UuidToString(vm_uuid),
912 : UuidToString(vn_uuid), UuidToString(vmi_uuid),
913 : vm_name, vm_identifier, host_ifname, vm_ifname,
914 : vm_namespace, version_);
915 :
916 0 : return new VmVnPortSubscribeEntry(vmi_type, host_ifname, version_, vm_uuid,
917 : vn_uuid, vmi_uuid, vm_name, vm_identifier,
918 0 : vm_ifname, vm_namespace);
919 0 : }
920 :
921 0 : void PortIpcHandler::MakeVmVnPortJson(const VmVnPortSubscribeEntry *entry,
922 : string &info, bool meta_info) const {
923 0 : contrail_rapidjson::Document doc;
924 0 : doc.SetObject();
925 :
926 0 : string str2 = UuidToString(entry->vm_uuid());
927 0 : AddMember("vm-uuid", str2.c_str(), &doc);
928 0 : str2 = UuidToString(entry->vn_uuid());
929 0 : AddMember("vn-uuid", str2.c_str(), &doc);
930 0 : str2 = UuidToString(entry->vmi_uuid());
931 0 : AddMember("vmi-uuid", str2.c_str(), &doc);
932 0 : AddMember("vm-id", entry->vm_identifier().c_str(), &doc);
933 0 : AddMember("vm-name", entry->vm_name().c_str(), &doc);
934 0 : AddMember("host-ifname", entry->ifname().c_str(), &doc);
935 0 : AddMember("vm-ifname", entry->vm_ifname().c_str(), &doc);
936 0 : AddMember("vm-namespace", entry->vm_namespace().c_str(), &doc);
937 :
938 0 : if (meta_info) {
939 0 : AddMember("author", agent_->program_name().c_str(), &doc);
940 0 : string now = duration_usecs_to_string(UTCTimestampUsec());
941 0 : AddMember("time", now.c_str(), &doc);
942 0 : }
943 :
944 0 : contrail_rapidjson::StringBuffer buffer;
945 0 : contrail_rapidjson::PrettyWriter<contrail_rapidjson::StringBuffer> writer(buffer);
946 0 : doc.Accept(writer);
947 0 : info = buffer.GetString();
948 0 : return;
949 0 : }
950 :
951 0 : bool PortIpcHandler::WriteJsonToFile(VmVnPortSubscribeEntry *entry) const {
952 0 : string vmvn_dir = vmvn_dir_ + "/" + entry->vm_name();
953 0 : fs::path base_dir(vmvn_dir);
954 0 : if (fs::exists(base_dir) == false) {
955 0 : if (!fs::create_directories(base_dir)) {
956 0 : string err_msg = "Creating directory " + vmvn_dir + " failed";
957 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
958 0 : return false;
959 0 : }
960 : }
961 :
962 0 : string filename = vmvn_dir + "/" + UuidToString(entry->vmi_uuid());
963 0 : fs::path file_path(filename);
964 : /* Don't overwrite if the file already exists */
965 0 : if (fs::exists(file_path)) {
966 0 : return true;
967 : }
968 :
969 0 : string info;
970 0 : MakeVmVnPortJson(entry, info, true);
971 0 : if (info.empty()) {
972 0 : LOG(ERROR, "Error producing entry JSON for VM " << entry->vm_name());
973 0 : return false;
974 : }
975 0 : std::ofstream fs(filename.c_str());
976 0 : if (fs.fail()) {
977 0 : LOG(ERROR, "Cannot open file " << filename << " for writing");
978 0 : return false;
979 : }
980 0 : bool output = (fs << info).good();
981 0 : fs.close();
982 0 : if (!output) {
983 0 : LOG(ERROR, "Cannot write JSON to the file " << filename);
984 0 : fs::remove(file_path);
985 : }
986 :
987 0 : return output;
988 0 : }
989 :
990 0 : bool PortIpcHandler::DeleteVmVnPort(const boost::uuids::uuid &vm_uuid,
991 : string &err_msg) {
992 : uint64_t version;
993 0 : bool failed = false;
994 0 : string vmvn_dir = vmvn_dir_ + "/" + UuidToString(vm_uuid);
995 0 : std::set<boost::uuids::uuid> vmi_uuid_set;
996 :
997 0 : if (!port_subscribe_table_->VmVnToVmiSet(vm_uuid, vmi_uuid_set))
998 0 : return false;
999 :
1000 0 : std::set<boost::uuids::uuid>::iterator it = vmi_uuid_set.begin();
1001 0 : while (it != vmi_uuid_set.end()) {
1002 0 : boost::uuids::uuid vmi_uuid = *it;
1003 : const PortSubscribeTable::VmiEntry *vmi_entry =
1004 0 : port_subscribe_table_->VmiToEntry(vmi_uuid);
1005 : PortSubscribeEntryPtr entry =
1006 : port_subscribe_table_->GetVmVnPort(vm_uuid,
1007 0 : vmi_entry->vn_uuid_, vmi_uuid);
1008 0 : if (entry.get() != NULL) {
1009 0 : version = entry->version();
1010 : } else {
1011 0 : version = 0;
1012 : }
1013 :
1014 0 : port_subscribe_table_->DeleteVmVnPort(vm_uuid,
1015 0 : vmi_entry->vn_uuid_, vmi_uuid);
1016 0 : CONFIG_TRACE(DeleteVmVnPortEnqueue, "Delete", UuidToString(vm_uuid),
1017 : UuidToString(vmi_entry->vn_uuid_), version);
1018 :
1019 0 : string file = vmvn_dir + "/" + UuidToString(vmi_uuid);
1020 0 : fs::path file_path(file);
1021 0 : if (fs::exists(file_path) && fs::is_regular_file(file_path)) {
1022 0 : if (remove(file.c_str())) {
1023 0 : err_msg += " Error deleting file " + file;
1024 0 : failed = true;
1025 : }
1026 : }
1027 0 : it++;
1028 0 : }
1029 :
1030 0 : if (failed)
1031 0 : return false;
1032 :
1033 : /* remove vm directory in vmvn_dir_ */
1034 0 : fs::path base_dir(vmvn_dir);
1035 0 : if (!fs::remove_all(base_dir)) {
1036 0 : string err_msg = "Deleting directory " + vmvn_dir + " failed";
1037 0 : CONFIG_TRACE(PortInfo, err_msg.c_str());
1038 0 : }
1039 :
1040 0 : return true;
1041 0 : }
1042 :
1043 0 : bool PortIpcHandler::DeleteVmVnPort(const string &json, const string &vm,
1044 : string &err_msg) {
1045 0 : boost::uuids::uuid vm_uuid = StringToUuid(vm);
1046 0 : if (vm_uuid == nil_uuid()) {
1047 0 : return true;
1048 : }
1049 :
1050 0 : DeleteVmVnPort(vm_uuid, err_msg);
1051 0 : return true;
1052 : }
1053 :
1054 0 : bool PortIpcHandler::GetVmVnCfgPort(const string &vm, string &info) const {
1055 0 : VmTable *vm_table = agent_->vm_table();
1056 0 : boost::uuids::uuid vm_uuid = vm_table->GetVmUuid(vm);
1057 0 : if (vm_uuid == nil_uuid()) {
1058 0 : return false;
1059 : }
1060 :
1061 0 : std::set<boost::uuids::uuid> vmi_uuid_set;
1062 0 : if (!port_subscribe_table_->VmVnToVmiSet(vm_uuid, vmi_uuid_set))
1063 0 : return false;
1064 :
1065 0 : std::set<boost::uuids::uuid>::iterator it = vmi_uuid_set.begin();
1066 0 : info = '[';
1067 : do {
1068 0 : boost::uuids::uuid vmi_uuid = *it;
1069 0 : if (!MakeJsonFromVmiConfig(vmi_uuid, info))
1070 0 : return false;
1071 0 : it++;
1072 0 : info += ',';
1073 0 : } while (it != vmi_uuid_set.end());
1074 0 : info.erase(info.size() - 1);
1075 0 : info += ']';
1076 :
1077 0 : return true;
1078 :
1079 0 : }
1080 :
1081 0 : bool PortIpcHandler::MakeJsonFromVmiConfig(const boost::uuids::uuid &vmi_uuid,
1082 : string &resp) const {
1083 : const PortSubscribeTable::VmiEntry *vmi_entry =
1084 0 : port_subscribe_table_->VmiToEntry(vmi_uuid);
1085 :
1086 0 : if (vmi_entry == NULL) {
1087 0 : resp = "Interface Entry not found for request. Retry";
1088 0 : return false;
1089 : }
1090 :
1091 0 : const VnEntry *vn = agent_->vn_table()->Find(vmi_entry->vn_uuid_);
1092 0 : if (vn == NULL) {
1093 0 : resp = "VirtualNetwork not found for request. Retry";
1094 0 : return false;
1095 : }
1096 :
1097 0 : contrail_rapidjson::Document doc;
1098 0 : doc.SetObject();
1099 0 : contrail_rapidjson::Document::AllocatorType &a = doc.GetAllocator();
1100 :
1101 0 : string str1 = UuidToString(vmi_uuid);
1102 0 : AddMember("id", str1.c_str(), &doc);
1103 :
1104 0 : string str2 = UuidToString(vmi_entry->vm_uuid_);
1105 0 : AddMember("vm-uuid", str2.c_str(), &doc);
1106 :
1107 0 : string str5 = UuidToString(vmi_entry->vn_uuid_);
1108 0 : AddMember("vn-id", str5.c_str(), &doc);
1109 0 : AddMember("vn-name", vn->GetName().c_str(), &doc);
1110 :
1111 0 : AddMember("mac-address", vmi_entry->mac_.c_str(), &doc);
1112 0 : doc.AddMember("sub-interface", (bool)vmi_entry->sub_interface_, a);
1113 0 : doc.AddMember("vlan-id", (int)vmi_entry->vlan_tag_, a);
1114 :
1115 0 : if (vmi_entry->vmi_cfg != NULL) {
1116 : const std::vector<autogen::KeyValuePair> annotations =
1117 0 : vmi_entry->vmi_cfg->annotations();
1118 0 : if (annotations.size()) {
1119 0 : string str6;
1120 0 : contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
1121 0 : contrail_rapidjson::Value array(contrail_rapidjson::kArrayType);
1122 : std::vector<autogen::KeyValuePair>::const_iterator it =
1123 0 : annotations.begin();
1124 0 : while (it != annotations.end()) {
1125 0 : str6 = "{" + it->key + ":" + it->value + "}";
1126 0 : val.SetString(str6.c_str(), a);
1127 0 : array.PushBack(val, a);
1128 0 : it++;
1129 : }
1130 0 : doc.AddMember("annotations", array, a);
1131 0 : }
1132 0 : }
1133 :
1134 0 : contrail_rapidjson::StringBuffer buffer;
1135 : contrail_rapidjson::PrettyWriter<contrail_rapidjson::StringBuffer>
1136 0 : writer(buffer);
1137 0 : doc.Accept(writer);
1138 0 : resp += buffer.GetString();
1139 0 : return true;
1140 0 : }
1141 :
1142 0 : bool PortIpcHandler::GetVmVnPort(const string &vm, const string &vmi,
1143 : string &info) const {
1144 0 : boost::uuids::uuid vm_uuid = StringToUuid(vm);
1145 0 : if (vm_uuid == nil_uuid()) {
1146 0 : return false;
1147 : }
1148 :
1149 0 : if (vmi.size() > 0) {
1150 0 : info = '[';
1151 0 : boost::uuids::uuid vmi_uuid = StringToUuid(vmi);
1152 0 : if (!MakeJsonFromVmi(vmi_uuid, info))
1153 0 : return false;
1154 0 : info += ']';
1155 0 : return true;
1156 : }
1157 :
1158 0 : std::set<boost::uuids::uuid> vmi_uuid_set;
1159 0 : if (!port_subscribe_table_->VmVnToVmiSet(vm_uuid, vmi_uuid_set))
1160 0 : return false;
1161 :
1162 0 : std::set<boost::uuids::uuid>::iterator it = vmi_uuid_set.begin();
1163 0 : info = '[';
1164 : do {
1165 0 : boost::uuids::uuid vmi_uuid = *it;
1166 0 : if (!MakeJsonFromVmi(vmi_uuid, info))
1167 0 : return false;
1168 0 : it++;
1169 0 : info += ',';
1170 0 : } while (it != vmi_uuid_set.end());
1171 0 : info.erase(info.size() - 1);
1172 0 : info += ']';
1173 :
1174 0 : return true;
1175 0 : }
1176 :
1177 0 : bool PortIpcHandler::MakeJsonFromVmi(
1178 : const boost::uuids::uuid &vmi_uuid, string &resp) const {
1179 0 : InterfaceConstRef intf_ref = agent_->interface_table()->FindVmi(vmi_uuid);
1180 0 : const VmInterface *vmi = static_cast<const VmInterface *>(intf_ref.get());
1181 0 : if (vmi == NULL) {
1182 0 : resp = "Interface not found for request. Retry";
1183 0 : return false;
1184 : }
1185 :
1186 0 : const VmEntry *vm = vmi->vm();
1187 0 : if (vm == NULL) {
1188 0 : resp = "VirtualMachine not found for request. Retry";
1189 0 : return false;
1190 : }
1191 :
1192 0 : const VnEntry *vn = vmi->vn();
1193 0 : if (vn == NULL) {
1194 0 : resp = "VirtualNetwork not found for request. Retry";
1195 0 : return false;
1196 : }
1197 :
1198 0 : const VnIpam *ipam_v4 = vn->GetIpam(vmi->primary_ip_addr());
1199 0 : const VnIpam *ipam_v6 = vn->GetIpam(vmi->primary_ip6_addr());
1200 0 : if ((ipam_v4 == NULL) && (ipam_v6 == NULL)) {
1201 0 : resp = "Missing IPAM entry for request. Retry";
1202 0 : return false;
1203 : }
1204 :
1205 0 : contrail_rapidjson::Document doc;
1206 0 : doc.SetObject();
1207 0 : contrail_rapidjson::Document::AllocatorType &a = doc.GetAllocator();
1208 :
1209 0 : string str1 = UuidToString(vmi->GetUuid());
1210 0 : AddMember("id", str1.c_str(), &doc);
1211 :
1212 0 : string str2 = UuidToString(vm->GetUuid());
1213 0 : AddMember("instance-id", str2.c_str(), &doc);
1214 :
1215 0 : string str3 = UuidToString(vn->GetUuid());
1216 0 : AddMember("vn-id", str3.c_str(), &doc);
1217 :
1218 0 : string str4 = UuidToString(vmi->vm_project_uuid());
1219 0 : AddMember("vm-project-id", str4.c_str(), &doc);
1220 :
1221 0 : string str5 = vmi->vm_mac().ToString();
1222 0 : AddMember("mac-address", str5.c_str(), &doc);
1223 0 : AddMember("system-name", vmi->name().c_str(), &doc);
1224 0 : doc.AddMember("rx-vlan-id", (int)vmi->rx_vlan_id(), a);
1225 0 : doc.AddMember("tx-vlan-id", (int)vmi->tx_vlan_id(), a);
1226 0 : doc.AddMember("vhostuser-mode", (int)vmi->vhostuser_mode(), a);
1227 :
1228 0 : if (ipam_v4) {
1229 0 : string str6 = vmi->primary_ip_addr().to_string();
1230 0 : AddMember("ip-address", str6.c_str(), &doc);
1231 0 : doc.AddMember("plen", ipam_v4->plen, a);
1232 0 : string str7 = ipam_v4->dns_server.to_v4().to_string();
1233 0 : AddMember("dns-server", str7.c_str(), &doc);
1234 0 : string str8 = ipam_v4->default_gw.to_v4().to_string();
1235 0 : AddMember("gateway", str8.c_str(), &doc);
1236 0 : }
1237 :
1238 0 : if (ipam_v6) {
1239 0 : string str6 = vmi->primary_ip6_addr().to_string();
1240 0 : AddMember("v6-ip-address", str6.c_str(), &doc);
1241 0 : string str7 = ipam_v6->dns_server.to_v6().to_string();
1242 0 : AddMember("v6-dns-server", str7.c_str(), &doc);
1243 0 : string str8 = ipam_v6->default_gw.to_v6().to_string();
1244 0 : AddMember("v6-gateway", str8.c_str(), &doc);
1245 0 : }
1246 :
1247 0 : AddMember("author", agent_->program_name().c_str(), &doc);
1248 0 : string now = duration_usecs_to_string(UTCTimestampUsec());
1249 0 : AddMember("time", now.c_str(), &doc);
1250 :
1251 0 : contrail_rapidjson::StringBuffer buffer;
1252 0 : contrail_rapidjson::PrettyWriter<contrail_rapidjson::StringBuffer> writer(buffer);
1253 0 : doc.Accept(writer);
1254 0 : resp += buffer.GetString();
1255 0 : return true;
1256 0 : }
|