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