Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include <string>
5 : #include <sandesh/sandesh_trace.h>
6 : #include <port_ipc/port_ipc_types.h>
7 : #include <cmn/agent_cmn.h>
8 : #include <init/agent_param.h>
9 : #include <oper/interface_common.h>
10 : #include <controller/controller_init.h>
11 : #include "port_subscribe_table.h"
12 : #include "port_ipc_handler.h"
13 :
14 : using namespace autogen;
15 : using boost::uuids::nil_uuid;
16 :
17 : /////////////////////////////////////////////////////////////////////////////
18 : // Init/Shutdown routines
19 : /////////////////////////////////////////////////////////////////////////////
20 3 : void PortSubscribeTable::InitDone() {
21 : // Register with config DB table for vm-port UUID to IFNode mapping
22 3 : vmi_config_table_ = (static_cast<IFMapAgentTable *>
23 3 : (IFMapTable::FindTable(agent_->db(),
24 : "virtual-machine-interface")));
25 6 : vmi_config_listener_id_ = vmi_config_table_->Register
26 3 : (boost::bind(&PortSubscribeTable::Notify, this, _1, _2));
27 3 : }
28 :
29 3 : void PortSubscribeTable::Shutdown() {
30 3 : DBTable::DBStateClear(vmi_config_table_, vmi_config_listener_id_);
31 3 : vmi_config_table_->Unregister(vmi_config_listener_id_);
32 3 : }
33 :
34 : /////////////////////////////////////////////////////////////////////////////
35 : // PortSubscribeEntry routines
36 : /////////////////////////////////////////////////////////////////////////////
37 24 : PortSubscribeEntry::PortSubscribeEntry(Type type, const std::string &ifname,
38 24 : int32_t version) :
39 24 : type_(type), ifname_(ifname), version_(version) {
40 24 : }
41 :
42 24 : PortSubscribeEntry::~PortSubscribeEntry() {
43 24 : }
44 :
45 : // Only version number is modifiable
46 0 : void PortSubscribeEntry::Update(const PortSubscribeEntry *rhs) {
47 0 : version_ = rhs->version_;
48 0 : }
49 :
50 24 : const char *PortSubscribeEntry::TypeToString(Type type) {
51 24 : switch (type) {
52 24 : case VMPORT:
53 24 : return "VM Port";
54 : break;
55 :
56 0 : case NAMESPACE:
57 0 : return "Namespace Port";
58 : break;
59 :
60 0 : case REMOTE_PORT:
61 0 : return "Remote Port";
62 : break;
63 :
64 0 : default:
65 0 : break;
66 : }
67 :
68 0 : return "Invalid";
69 : }
70 :
71 : /////////////////////////////////////////////////////////////////////////////
72 : // VmiSubscribeEntry routines
73 : /////////////////////////////////////////////////////////////////////////////
74 24 : VmiSubscribeEntry::VmiSubscribeEntry(PortSubscribeEntry::Type type,
75 : const std::string &ifname,
76 : uint32_t version,
77 : const boost::uuids::uuid &vmi_uuid,
78 : const boost::uuids::uuid vm_uuid,
79 : const std::string &vm_name,
80 : const boost::uuids::uuid &vn_uuid,
81 : const boost::uuids::uuid &project_uuid,
82 : const Ip4Address &ip4_addr,
83 : const Ip6Address &ip6_addr,
84 : const std::string &mac_addr,
85 : uint16_t tx_vlan_id, uint16_t rx_vlan_id,
86 24 : uint8_t vhostuser_mode, uint8_t link_state) :
87 24 : PortSubscribeEntry(type, ifname, version), vmi_uuid_(vmi_uuid),
88 48 : vm_uuid_(vm_uuid), vm_name_(vm_name), vn_uuid_(vn_uuid),
89 24 : project_uuid_(project_uuid), ip4_addr_(ip4_addr), ip6_addr_(ip6_addr),
90 24 : mac_addr_(mac_addr), tx_vlan_id_(tx_vlan_id), rx_vlan_id_(rx_vlan_id),
91 24 : vhostuser_mode_(vhostuser_mode), link_state_(link_state) {
92 24 : }
93 :
94 36 : VmiSubscribeEntry::~VmiSubscribeEntry() {
95 36 : }
96 :
97 0 : void VmiSubscribeEntry::Update(const PortSubscribeEntry *rhs) {
98 0 : PortSubscribeEntry::Update(rhs);
99 0 : }
100 :
101 12 : void VmiSubscribeEntry::OnAdd(Agent *agent, PortSubscribeTable *table) const {
102 12 : uint16_t tx_vlan_id_p = VmInterface::kInvalidVlanId;
103 12 : uint16_t rx_vlan_id_p = VmInterface::kInvalidVlanId;
104 12 : string port = Agent::NullString();
105 12 : Interface::Transport transport = Interface::TRANSPORT_ETHERNET;
106 12 : if (agent->params()->isVmwareMode()) {
107 0 : tx_vlan_id_p = tx_vlan_id_;
108 0 : rx_vlan_id_p = rx_vlan_id_;
109 0 : if (tx_vlan_id_p != VmInterface::kInvalidVlanId ||
110 : rx_vlan_id_p != VmInterface::kInvalidVlanId) {
111 : // In case of netns instance transport mode and
112 : // parent interface shouldnt be set
113 0 : port = agent->params()->vmware_physical_port();
114 0 : transport = Interface::TRANSPORT_VIRTUAL;
115 : }
116 : }
117 :
118 12 : if ((agent->vrouter_on_nic_mode() == true ||
119 12 : agent->vrouter_on_host_dpdk() == true) &&
120 0 : type_ == PortSubscribeEntry::VMPORT) {
121 0 : transport = Interface::TRANSPORT_PMD;
122 : }
123 :
124 : // Add the interface
125 12 : VmInterface::NovaAdd(agent->interface_table(), vmi_uuid_, ifname_,
126 12 : ip4_addr_, mac_addr_, vm_name_, project_uuid_,
127 12 : tx_vlan_id_p, rx_vlan_id_p, port, ip6_addr_,
128 12 : vhostuser_mode_, transport, link_state_);
129 :
130 : // Notify controller module about new port
131 12 : if (type_ == PortSubscribeEntry::NAMESPACE)
132 0 : return;
133 :
134 : VNController::ControllerWorkQueueDataType
135 12 : data(new ControllerVmiSubscribeData(false, vmi_uuid_, vm_uuid_));
136 12 : agent->controller()->Enqueue(data);
137 12 : }
138 :
139 12 : void VmiSubscribeEntry::OnDelete(Agent *agent, PortSubscribeTable *table)
140 : const {
141 12 : VmInterface::Delete(agent->interface_table(), vmi_uuid_,
142 : VmInterface::INSTANCE_MSG);
143 12 : if (type_ == PortSubscribeEntry::NAMESPACE)
144 0 : return;
145 :
146 : VNController::ControllerWorkQueueDataType
147 12 : data(new ControllerVmiSubscribeData(true, vmi_uuid_, vm_uuid_));
148 12 : agent->controller()->Enqueue(data);
149 12 : }
150 :
151 38 : bool VmiSubscribeEntry::MatchVn(const boost::uuids::uuid &u) const {
152 38 : return vn_uuid_ == u;
153 : }
154 :
155 38 : bool VmiSubscribeEntry::MatchVm(const boost::uuids::uuid &u) const {
156 38 : return vm_uuid_ == u;
157 : }
158 :
159 : /////////////////////////////////////////////////////////////////////////////
160 : // VmVnPortSubscribeEntry routines
161 : /////////////////////////////////////////////////////////////////////////////
162 0 : VmVnPortSubscribeEntry::VmVnPortSubscribeEntry
163 : (PortSubscribeEntry::Type type, const std::string &ifname, uint32_t version,
164 : const boost::uuids::uuid &vm_uuid, const boost::uuids::uuid &vn_uuid,
165 : const boost::uuids::uuid &vmi_uuid, const std::string &vm_name,
166 : const std::string &vm_identifier, const std::string &vm_ifname,
167 0 : const std::string &vm_namespace) :
168 0 : PortSubscribeEntry(type, ifname, version), vm_uuid_(vm_uuid),
169 0 : vn_uuid_(vn_uuid), vm_name_(vm_name), vm_identifier_(vm_identifier),
170 0 : vm_ifname_(vm_ifname), vm_namespace_(vm_namespace), vmi_uuid_(vmi_uuid) {
171 0 : }
172 :
173 0 : VmVnPortSubscribeEntry::~VmVnPortSubscribeEntry() {
174 0 : }
175 :
176 0 : void VmVnPortSubscribeEntry::Update(const PortSubscribeEntry *rhs) {
177 0 : PortSubscribeEntry::Update(rhs);
178 0 : }
179 :
180 0 : void VmVnPortSubscribeEntry::OnAdd(Agent *agent, PortSubscribeTable *table)
181 : const {
182 0 : VmInterface::SetIfNameReq(agent->interface_table(), vmi_uuid_, ifname_);
183 :
184 0 : }
185 :
186 0 : void VmVnPortSubscribeEntry::OnDelete(Agent *agent, PortSubscribeTable *table)
187 : const {
188 0 : VmInterface::DeleteIfNameReq(agent->interface_table(), vmi_uuid_);
189 0 : }
190 :
191 0 : bool VmVnPortSubscribeEntry::MatchVn(const boost::uuids::uuid &u) const {
192 0 : if (vn_uuid_ == nil_uuid())
193 0 : return true;
194 :
195 0 : return vn_uuid_ == u;
196 : }
197 :
198 0 : bool VmVnPortSubscribeEntry::MatchVm(const boost::uuids::uuid &u) const {
199 0 : return vm_uuid_ == u;
200 : }
201 :
202 : /////////////////////////////////////////////////////////////////////////////
203 : // PortSubscribeTable routines
204 : /////////////////////////////////////////////////////////////////////////////
205 3 : PortSubscribeTable::PortSubscribeTable(Agent *agent) :
206 6 : agent_(agent), interface_table_(agent->interface_table()),
207 3 : controller_(agent->controller()),
208 6 : vmi_config_table_(NULL), vmi_config_listener_id_(DBTableBase::kInvalidId) {
209 3 : }
210 :
211 6 : PortSubscribeTable::~PortSubscribeTable() {
212 3 : assert(vmi_tree_.size() == 0);
213 6 : }
214 :
215 12 : void PortSubscribeTable::AddVmi(const boost::uuids::uuid &u,
216 : PortSubscribeEntryPtr entry) {
217 12 : std::scoped_lock lock(mutex_);
218 : std::pair<VmiTree::iterator, bool> ret =
219 12 : vmi_tree_.insert(std::make_pair(u, entry));
220 12 : if (ret.second == false) {
221 : // Could be a port add for an exisiting VMI with a different VM.
222 : // If so need to handle as a del and add.
223 : VmiSubscribeEntry *new_entry =
224 0 : dynamic_cast<VmiSubscribeEntry *>(entry.get());
225 : VmiSubscribeEntry *old_entry =
226 0 : dynamic_cast<VmiSubscribeEntry *>(ret.first->second.get());
227 0 : if (old_entry->vm_uuid() != new_entry->vm_uuid()) {
228 0 : ret.first->second->OnDelete(agent_, this);
229 0 : vmi_tree_.erase(ret.first);
230 0 : ret = vmi_tree_.insert(std::make_pair(u, entry));
231 : } else {
232 0 : ret.first->second->Update(entry.get());
233 : }
234 : }
235 :
236 12 : ret.first->second->OnAdd(agent_, this);
237 12 : }
238 :
239 14 : void PortSubscribeTable::DeleteVmi(const boost::uuids::uuid &u) {
240 14 : std::scoped_lock lock(mutex_);
241 14 : VmiTree::iterator it = vmi_tree_.find(u);
242 14 : if (it == vmi_tree_.end())
243 2 : return;
244 :
245 12 : it->second->OnDelete(agent_, this);
246 12 : vmi_tree_.erase(it);
247 14 : }
248 :
249 14 : PortSubscribeEntryPtr PortSubscribeTable::GetVmi(const boost::uuids::uuid &u)
250 : const {
251 14 : std::scoped_lock lock(mutex_);
252 14 : VmiTree::const_iterator it = vmi_tree_.find(u);
253 14 : if (it == vmi_tree_.end())
254 2 : return PortSubscribeEntryPtr();
255 :
256 12 : return it->second;
257 14 : }
258 :
259 : /*
260 : * Process add of vm-vn subscribe entry.
261 : * Add an entry to vmvn_subscribe_tree_
262 : * If VMI config was already received for port then
263 : * - find vmi-uuid from * vmvn_to_vmi_tree_
264 : * - ifmap config resync will be done once vmi is added
265 : */
266 0 : void PortSubscribeTable::AddVmVnPort(const boost::uuids::uuid &vm_uuid,
267 : const boost::uuids::uuid &vn_uuid,
268 : const boost::uuids::uuid &vmi_uuid,
269 : PortSubscribeEntryPtr entry) {
270 0 : std::scoped_lock lock(mutex_);
271 : std::pair<VmVnTree::iterator, bool> ret = vmvn_subscribe_tree_.insert
272 0 : (make_pair(VmVnUuidEntry(vm_uuid, vn_uuid, vmi_uuid),entry));
273 0 : if (ret.second == false) {
274 0 : ret.first->second->Update(entry.get());
275 : }
276 :
277 : // Find VMI for the vm-vn
278 : //boost::uuids::uuid vmi_uuid = VmVnToVmiNoLock(vm_uuid);
279 0 : if (vmi_uuid.is_nil())
280 0 : return;
281 :
282 : // If entry is found, it means IFNode for VMI already present
283 : // Enqueue vm-add request
284 : VmVnPortSubscribeEntry *vmvn_entry =
285 0 : static_cast<VmVnPortSubscribeEntry *>(entry.get());
286 0 : vmvn_entry->set_vmi_uuid(vmi_uuid);
287 0 : vmvn_entry->OnAdd(agent_, this);
288 0 : }
289 :
290 0 : void PortSubscribeTable::DeleteVmVnPort
291 : (const boost::uuids::uuid &vm_uuid,
292 : const boost::uuids::uuid &vn_uuid,
293 : const boost::uuids::uuid &vmi_uuid) {
294 0 : std::scoped_lock lock(mutex_);
295 : VmVnTree::iterator it =
296 0 : vmvn_subscribe_tree_.find(VmVnUuidEntry(vm_uuid, vn_uuid, vmi_uuid));
297 0 : if (it == vmvn_subscribe_tree_.end())
298 0 : return;
299 :
300 0 : it->second->OnDelete(agent_, this);
301 0 : vmvn_subscribe_tree_.erase(it);
302 0 : }
303 :
304 70 : PortSubscribeEntryPtr PortSubscribeTable::GetVmVnPortNoLock
305 : (const boost::uuids::uuid &vm_uuid,
306 : const boost::uuids::uuid &vn_uuid,
307 : const boost::uuids::uuid &vmi_uuid) {
308 : VmVnTree::iterator it =
309 70 : vmvn_subscribe_tree_.find(VmVnUuidEntry(vm_uuid, vn_uuid, vmi_uuid));
310 70 : if (it == vmvn_subscribe_tree_.end())
311 70 : return PortSubscribeEntryPtr();
312 :
313 0 : return it->second;
314 : }
315 :
316 0 : PortSubscribeEntryPtr PortSubscribeTable::GetVmVnPort
317 : (const boost::uuids::uuid &vm_uuid,
318 : const boost::uuids::uuid &vn_uuid,
319 : const boost::uuids::uuid &vmi_uuid) {
320 0 : std::scoped_lock lock(mutex_);
321 0 : return GetVmVnPortNoLock(vm_uuid, vn_uuid, vmi_uuid);
322 0 : }
323 :
324 : /////////////////////////////////////////////////////////////////////////////
325 : // virtual-machine-interface table handler
326 : /////////////////////////////////////////////////////////////////////////////
327 30 : void PortSubscribeTable::Notify(DBTablePartBase *partition, DBEntryBase *e) {
328 30 : IFMapNode *node = static_cast<IFMapNode *>(e);
329 30 : State *state = static_cast<State *>(e->GetState(partition->parent(),
330 : vmi_config_listener_id_));
331 30 : if (node->IsDeleted()) {
332 14 : if (state == NULL)
333 14 : return;
334 14 : if (state->uuid_ != nil_uuid())
335 14 : uuid_ifnode_tree_.erase(state->uuid_);
336 14 : node->ClearState(partition->parent(), vmi_config_listener_id_);
337 14 : delete state;
338 14 : return;
339 : }
340 :
341 : // Allocate DBState
342 16 : if (state == NULL) {
343 14 : state = new State();
344 14 : node->SetState(partition->parent(), vmi_config_listener_id_, state);
345 : }
346 :
347 : boost::uuids::uuid u;
348 : VirtualMachineInterface *cfg =
349 16 : static_cast <VirtualMachineInterface *> (node->GetObject());
350 16 : if (cfg != NULL) {
351 16 : autogen::IdPermsType id_perms = cfg->id_perms();
352 16 : CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
353 16 : }
354 :
355 : // Update UUID tree
356 16 : if (state->uuid_ != u) {
357 : // Remove old-uuid
358 14 : if (state->uuid_ != nil_uuid()) {
359 0 : uuid_ifnode_tree_.erase(state->uuid_);
360 0 : state->uuid_ = nil_uuid();
361 : }
362 :
363 : // Set new-uuid
364 14 : if (u != nil_uuid()) {
365 14 : state->uuid_ = u;
366 14 : uuid_ifnode_tree_.insert(std::make_pair(u, node));
367 : }
368 : }
369 : }
370 :
371 15 : IFMapNode *PortSubscribeTable::UuidToIFNode(const boost::uuids::uuid &u) const {
372 15 : UuidToIFNodeTree::const_iterator it;
373 15 : it = uuid_ifnode_tree_.find(u);
374 15 : if (it == uuid_ifnode_tree_.end()) {
375 15 : return NULL;
376 : }
377 0 : return it->second;
378 : }
379 :
380 0 : const PortSubscribeTable::VmiEntry *PortSubscribeTable::VmiToEntry
381 : (const boost::uuids::uuid &vmi_uuid) const {
382 0 : VmiToVmVnTree::const_iterator it = vmi_to_vmvn_tree_.find(vmi_uuid);
383 0 : if (it == vmi_to_vmvn_tree_.end())
384 0 : return NULL;
385 :
386 0 : return &it->second;
387 : }
388 :
389 70 : static void CopyVmiConfigToInfo(PortSubscribeTable::VmiEntry *entry,
390 : const VmInterfaceConfigData *data) {
391 70 : entry->vm_uuid_ = data->vm_uuid_;
392 70 : entry->vn_uuid_ = data->vn_uuid_;
393 70 : entry->sub_interface_ = (entry->parent_vmi_.is_nil() == false);
394 70 : entry->parent_vmi_ = data->parent_vmi_;
395 70 : entry->vlan_tag_ = data->rx_vlan_id_;
396 70 : entry->vhostuser_mode_ = data->vhostuser_mode_;
397 70 : entry->mac_ = data->vm_mac_;
398 70 : entry->vmi_cfg = data->GetVmiCfg();
399 70 : }
400 :
401 : /*
402 : * Update config tables built from VMI IFnode
403 : * - Adds entry into vmi_to_vmvn_tree_
404 : * - Adds entry to vmvn_to_vmi_tree_
405 : */
406 70 : void PortSubscribeTable::UpdateVmiIfnodeInfo
407 : (const boost::uuids::uuid &vmi_uuid, const VmInterfaceConfigData *data) {
408 : // Find entry from vmi to vm-vn tree first
409 70 : VmiToVmVnTree::iterator it;
410 70 : it = vmi_to_vmvn_tree_.find(vmi_uuid);
411 :
412 70 : if (it != vmi_to_vmvn_tree_.end()) {
413 : // Nothing to do if entry already present and vm/vn match
414 131 : if (it->second.vm_uuid_ != data->vm_uuid_ ||
415 65 : it->second.vn_uuid_ != data->vn_uuid_) {
416 : // If an entry already present and VM/VN are different, remove the
417 : // reverse entry first and then update with new entry
418 7 : vmvn_to_vmi_tree_.erase(VmVnUuidEntry(it->second.vm_uuid_,
419 7 : it->second.vn_uuid_,
420 : vmi_uuid));
421 7 : VmVnUuidEntry entry(data->vm_uuid_, data->vn_uuid_, vmi_uuid);
422 7 : vmvn_to_vmi_tree_.insert(std::make_pair(entry, vmi_uuid));
423 7 : }
424 :
425 : // Update data fields
426 66 : CopyVmiConfigToInfo(&it->second, data);
427 : } else {
428 : // Entry not present add to vmi_to_vmvn_tree_ and vmvn_to_vmi_tree_
429 4 : VmVnUuidEntry entry(data->vm_uuid_, data->vn_uuid_, vmi_uuid);
430 4 : vmvn_to_vmi_tree_.insert(std::make_pair(entry, vmi_uuid));
431 4 : VmiEntry vmi_entry;
432 4 : CopyVmiConfigToInfo(&vmi_entry, data);
433 4 : vmi_to_vmvn_tree_.insert(std::make_pair(vmi_uuid, vmi_entry));
434 4 : }
435 70 : }
436 :
437 : /*
438 : * VMI IFNode config added. Build vmi_to_vmvn_tree_ and vmvn_to_vmi_tree from
439 : * interface configuration. It will be used for vm-vn based subscriptions
440 : *
441 : * If the vm-vn port subscription is already received, the message would have
442 : * been ignored since vmi-uuid was not known. Process the vm-vn port
443 : * subscription now
444 : */
445 70 : void PortSubscribeTable::HandleVmiIfnodeAdd(const boost::uuids::uuid &vmi_uuid,
446 : const VmInterfaceConfigData *data) {
447 70 : std::scoped_lock lock(mutex_);
448 70 : UpdateVmiIfnodeInfo(vmi_uuid, data);
449 : // Add vm-interface if possible
450 : PortSubscribeEntryPtr entry_ref =
451 70 : GetVmVnPortNoLock(data->vm_uuid_, data->vn_uuid_, vmi_uuid);
452 70 : if (entry_ref.get() == NULL)
453 70 : return;
454 :
455 : VmVnPortSubscribeEntry *entry =
456 0 : dynamic_cast<VmVnPortSubscribeEntry *>(entry_ref.get());
457 : // Nothing to do if vmi-uuid doesnt change
458 0 : if (entry->vmi_uuid() == vmi_uuid) {
459 0 : return;
460 : }
461 :
462 : // vmi-uuid for vmvn-port entry changed. Delete old VMI and add new VMI
463 0 : if (entry->vmi_uuid().is_nil() == false) {
464 0 : entry->OnDelete(agent_, this);
465 : }
466 0 : entry->set_vmi_uuid(vmi_uuid);
467 0 : if (entry->vmi_uuid().is_nil() == false) {
468 0 : entry->OnAdd(agent_, this);
469 : }
470 140 : }
471 :
472 : /*
473 : * Update config tables built from VMI IFnode
474 : * - Deletes entry from vmi_to_vmvn_tree_
475 : * - Deletes entry from vmvn_to_vmi_tree_
476 : */
477 12 : void PortSubscribeTable::DeleteVmiIfnodeInfo
478 : (const boost::uuids::uuid &vmi_uuid) {
479 12 : VmiToVmVnTree::iterator it;
480 12 : it = vmi_to_vmvn_tree_.find(vmi_uuid);
481 12 : if (it == vmi_to_vmvn_tree_.end()) {
482 10 : return;
483 : }
484 :
485 : // If an entry already present in vm-vn entry, delete entries from
486 : // vmi_to_vmvn_tree_ and vmvn_to_vmi_tree_
487 2 : vmvn_to_vmi_tree_.erase(VmVnUuidEntry(it->second.vm_uuid_,
488 2 : it->second.vn_uuid_,
489 : vmi_uuid));
490 2 : vmi_to_vmvn_tree_.erase(it);
491 : }
492 :
493 : /*
494 : * VMI IFNode config deleted. Remove entries from vmi_to_vmvn_tree_ and
495 : * vmvn_to_vmi_tree from interface configuration.
496 : *
497 : * VMI deletion happens only on deletion of vm-vn port subscription. So, dont
498 : * enqueue any VMI delete from here
499 : */
500 12 : void PortSubscribeTable::HandleVmiIfnodeDelete
501 : (const boost::uuids::uuid &vmi_uuid) {
502 12 : std::scoped_lock lock(mutex_);
503 12 : DeleteVmiIfnodeInfo(vmi_uuid);
504 12 : }
505 :
506 0 : void PortSubscribeTable::StaleWalk(uint64_t version) {
507 : // TODO : The tree can be modified in parallel. Must ensure synchronization
508 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
509 0 : if (!pih) {
510 0 : return;
511 : }
512 0 : VmiTree::iterator it = vmi_tree_.begin();
513 0 : while (it != vmi_tree_.end()) {
514 : VmiSubscribeEntry *entry =
515 0 : dynamic_cast<VmiSubscribeEntry *>(it->second.get());
516 0 : it++;
517 0 : if (entry->type() == PortSubscribeEntry::NAMESPACE)
518 0 : continue;
519 :
520 0 : if (entry->version() >= version) {
521 0 : continue;
522 : }
523 :
524 0 : std::string msg;
525 0 : pih->DeleteVmiUuidEntry(entry->vmi_uuid(), msg);
526 0 : }
527 :
528 : // Audit vm-vn port subscription entries
529 0 : VmVnTree::iterator vmvn_it = vmvn_subscribe_tree_.begin();
530 0 : while (vmvn_it != vmvn_subscribe_tree_.end()) {
531 : VmVnPortSubscribeEntry *entry =
532 0 : dynamic_cast<VmVnPortSubscribeEntry *>(vmvn_it->second.get());
533 0 : vmvn_it++;
534 0 : if (entry->type() == PortSubscribeEntry::NAMESPACE)
535 0 : continue;
536 :
537 0 : if (entry->version() >= version) {
538 0 : continue;
539 : }
540 :
541 0 : std::string msg;
542 0 : pih->DeleteVmVnPort(entry->vm_uuid(), msg);
543 0 : }
544 : }
545 :
546 : // Get port-subscribe-entry for a VMI
547 : // First looks at VMI subscription table. If not found, looks into
548 : // vmvn-port-subscribe table
549 70 : PortSubscribeEntryPtr PortSubscribeTable::Get
550 : (const boost::uuids::uuid &vmi_uuid,
551 : const boost::uuids::uuid &vm_uuid,
552 : const boost::uuids::uuid &vn_uuid) const {
553 70 : std::scoped_lock lock(mutex_);
554 70 : VmiTree::const_iterator it = vmi_tree_.find(vmi_uuid);
555 70 : if (it != vmi_tree_.end())
556 38 : return it->second;
557 :
558 : VmVnTree::const_iterator it1 =
559 32 : vmvn_subscribe_tree_.find(VmVnUuidEntry(vm_uuid, vn_uuid, vmi_uuid));
560 32 : if (it1 != vmvn_subscribe_tree_.end())
561 0 : return it1->second;
562 :
563 32 : return PortSubscribeEntryPtr();
564 70 : }
565 :
566 0 : bool PortSubscribeTable::VmVnToVmiSetNoLock
567 : (const boost::uuids::uuid &vm_uuid,
568 : std::set<boost::uuids::uuid> &vmi_uuid_set) const {
569 : VmVnToVmiTree::const_iterator it =
570 0 : vmvn_to_vmi_tree_.lower_bound(
571 0 : VmVnUuidEntry(vm_uuid, nil_uuid(), nil_uuid()));
572 :
573 0 : while (it != vmvn_to_vmi_tree_.end()) {
574 0 : if (it->first.vm_uuid_ == vm_uuid)
575 0 : vmi_uuid_set.insert(it->second);
576 0 : it++;
577 : }
578 :
579 0 : if (vmi_uuid_set.empty())
580 0 : return false;
581 :
582 0 : return true;
583 : }
584 :
585 0 : bool PortSubscribeTable::VmVnToVmiSet
586 : (const boost::uuids::uuid &vm_uuid,
587 : std::set<boost::uuids::uuid> &vmi_uuid_set) const {
588 0 : std::scoped_lock lock(mutex_);
589 0 : return VmVnToVmiSetNoLock(vm_uuid, vmi_uuid_set);
590 0 : }
591 :
592 : /////////////////////////////////////////////////////////////////////////////
593 : // Introspect routines
594 : /////////////////////////////////////////////////////////////////////////////
595 : class SandeshPortSubscribeTask : public Task {
596 : public:
597 0 : SandeshPortSubscribeTask(Agent *agent, const std::string &context) :
598 : Task(agent->task_scheduler()->GetTaskId(kTaskHttpRequstHandler), 0),
599 0 : agent_(agent),
600 0 : table_(agent->port_ipc_handler()->port_subscribe_table()),
601 0 : context_(context) {
602 0 : }
603 0 : virtual ~SandeshPortSubscribeTask() { }
604 :
605 : protected:
606 : Agent *agent_;
607 : const PortSubscribeTable *table_;
608 : std::string context_;
609 : DISALLOW_COPY_AND_ASSIGN(SandeshPortSubscribeTask);
610 : };
611 :
612 : // vmi_tree_ routes
613 : class SandeshVmiPortSubscribeTask : public SandeshPortSubscribeTask {
614 : public:
615 0 : SandeshVmiPortSubscribeTask(Agent *agent, const std::string &context,
616 : const std::string &ifname,
617 0 : const boost::uuids::uuid &vmi_uuid) :
618 : SandeshPortSubscribeTask(agent, context),
619 0 : ifname_(ifname), vmi_uuid_(vmi_uuid) {
620 0 : }
621 0 : virtual ~SandeshVmiPortSubscribeTask() { }
622 :
623 : virtual bool Run();
624 0 : std::string Description() const { return "SandeshVmiPortSubscribeTask"; }
625 : private:
626 : std::string ifname_;
627 : boost::uuids::uuid vmi_uuid_;
628 : DISALLOW_COPY_AND_ASSIGN(SandeshVmiPortSubscribeTask);
629 : };
630 :
631 0 : bool SandeshVmiPortSubscribeTask::Run() {
632 0 : SandeshVmiPortSubscriptionResp *resp = new SandeshVmiPortSubscriptionResp();
633 :
634 0 : PortSubscribeTable::VmiTree::const_iterator it = table_->vmi_tree_.begin();
635 0 : std::vector<SandeshVmiPortSubscriptionInfo> port_list;
636 0 : while (it != table_->vmi_tree_.end()) {
637 : const VmiSubscribeEntry *entry =
638 0 : dynamic_cast<const VmiSubscribeEntry *> (it->second.get());
639 0 : it++;
640 :
641 0 : if ((ifname_.empty() == false) &&
642 0 : (entry->ifname().find(ifname_) == string::npos) ) {
643 0 : continue;
644 : }
645 :
646 0 : if (vmi_uuid_.is_nil() == false && entry->vmi_uuid() != vmi_uuid_) {
647 0 : continue;
648 : }
649 :
650 0 : SandeshVmiPortSubscriptionInfo info;
651 0 : info.set_ifname(entry->ifname());
652 0 : info.set_version(entry->version());
653 0 : info.set_vmi_uuid(UuidToString(entry->vmi_uuid()));
654 0 : info.set_vm_uuid(UuidToString(entry->vm_uuid()));
655 0 : info.set_vn_uuid(UuidToString(entry->vn_uuid()));
656 0 : info.set_vm_name(entry->vm_name());
657 0 : info.set_ip4_addr(entry->ip4_addr().to_string());
658 0 : info.set_ip6_addr(entry->ip6_addr().to_string());
659 0 : info.set_mac(entry->mac_addr());
660 0 : info.set_tx_vlan(entry->tx_vlan_id());
661 0 : info.set_rx_vlan(entry->rx_vlan_id());
662 0 : info.set_vhostuser_mode(entry->vhostuser_mode());
663 :
664 0 : port_list.push_back(info);
665 0 : }
666 0 : resp->set_port_list(port_list);
667 :
668 0 : resp->set_context(context_);
669 0 : resp->set_more(false);
670 0 : resp->Response();
671 0 : return true;
672 0 : }
673 :
674 0 : void FetchVmiPortSubscriptionReq::HandleRequest() const {
675 0 : Agent *agent = Agent::GetInstance();
676 0 : boost::uuids::uuid u = StringToUuid(get_vmi_uuid());
677 : SandeshVmiPortSubscribeTask *t =
678 0 : new SandeshVmiPortSubscribeTask(agent, context(), get_ifname(), u);
679 0 : agent->task_scheduler()->Enqueue(t);
680 0 : }
681 :
682 : // vmvn_subscribe_tree_ routes
683 : class SandeshVmVnPortSubscribeTask : public SandeshPortSubscribeTask {
684 : public:
685 0 : SandeshVmVnPortSubscribeTask(Agent *agent, const std::string &context,
686 : const std::string &ifname,
687 0 : const boost::uuids::uuid &vm_uuid) :
688 : SandeshPortSubscribeTask(agent, context),
689 0 : ifname_(ifname), vm_uuid_(vm_uuid) {
690 0 : }
691 0 : virtual ~SandeshVmVnPortSubscribeTask() { }
692 :
693 : virtual bool Run();
694 0 : std::string Description() const { return "SandeshVmVnPortSubscribeTask"; }
695 : private:
696 : std::string ifname_;
697 : boost::uuids::uuid vm_uuid_;
698 : DISALLOW_COPY_AND_ASSIGN(SandeshVmVnPortSubscribeTask);
699 : };
700 :
701 0 : bool SandeshVmVnPortSubscribeTask::Run() {
702 : SandeshVmVnPortSubscriptionResp *resp =
703 0 : new SandeshVmVnPortSubscriptionResp();
704 :
705 : PortSubscribeTable::VmVnTree::const_iterator it =
706 0 : table_->vmvn_subscribe_tree_.begin();
707 0 : std::vector<SandeshVmVnPortSubscriptionInfo> port_list;
708 0 : while (it != table_->vmvn_subscribe_tree_.end()) {
709 : const VmVnPortSubscribeEntry *entry =
710 0 : dynamic_cast<const VmVnPortSubscribeEntry *> (it->second.get());
711 0 : it++;
712 :
713 0 : if ((ifname_.empty() == false) &&
714 0 : (entry->ifname().find(ifname_) == string::npos) ) {
715 0 : continue;
716 : }
717 :
718 0 : if (vm_uuid_.is_nil() == false && entry->vm_uuid() != vm_uuid_) {
719 0 : continue;
720 : }
721 :
722 0 : SandeshVmVnPortSubscriptionInfo info;
723 0 : info.set_ifname(entry->ifname());
724 0 : info.set_version(entry->version());
725 0 : info.set_vm_uuid(UuidToString(entry->vm_uuid()));
726 0 : info.set_vn_uuid(UuidToString(nil_uuid()));
727 0 : info.set_vm_name(entry->vm_name());
728 0 : info.set_vm_identifier(entry->vm_identifier());
729 0 : info.set_vm_ifname(entry->vm_ifname());
730 0 : info.set_vm_namespace(entry->vm_namespace());
731 0 : info.set_vmi_uuid(UuidToString(entry->vmi_uuid()));
732 0 : port_list.push_back(info);
733 0 : }
734 0 : resp->set_port_list(port_list);
735 :
736 0 : resp->set_context(context_);
737 0 : resp->set_more(false);
738 0 : resp->Response();
739 0 : return true;
740 0 : }
741 :
742 0 : void FetchVmVnPortSubscriptionReq::HandleRequest() const {
743 0 : Agent *agent = Agent::GetInstance();
744 0 : boost::uuids::uuid u = StringToUuid(get_vm_uuid());
745 : SandeshVmVnPortSubscribeTask *t =
746 0 : new SandeshVmVnPortSubscribeTask(agent, context(), get_ifname(), u);
747 0 : agent->task_scheduler()->Enqueue(t);
748 0 : }
749 :
750 : // vmi_to_vmvn_tree_ routes
751 : class SandeshVmiToVmVnTask : public SandeshPortSubscribeTask {
752 : public:
753 0 : SandeshVmiToVmVnTask(Agent *agent, const std::string &context,
754 0 : const boost::uuids::uuid &vmi_uuid) :
755 : SandeshPortSubscribeTask(agent, context),
756 0 : vmi_uuid_(vmi_uuid) {
757 0 : }
758 0 : virtual ~SandeshVmiToVmVnTask() { }
759 :
760 : virtual bool Run();
761 0 : std::string Description() const { return "SandeshVmiToVmVnTask"; }
762 : private:
763 : boost::uuids::uuid vmi_uuid_;
764 : DISALLOW_COPY_AND_ASSIGN(SandeshVmiToVmVnTask);
765 : };
766 :
767 0 : bool SandeshVmiToVmVnTask::Run() {
768 0 : SandeshVmiToVmVnResp *resp = new SandeshVmiToVmVnResp();
769 :
770 : PortSubscribeTable::VmiToVmVnTree::const_iterator it =
771 0 : table_->vmi_to_vmvn_tree_.begin();
772 0 : std::vector<SandeshVmiToVmVnInfo> port_list;
773 0 : while (it != table_->vmi_to_vmvn_tree_.end()) {
774 0 : boost::uuids::uuid vmi_uuid = it->first;
775 0 : const PortSubscribeTable::VmiEntry *vmi_entry = &it->second;
776 0 : boost::uuids::uuid vm_uuid = vmi_entry->vm_uuid_;
777 0 : boost::uuids::uuid vn_uuid = vmi_entry->vn_uuid_;
778 0 : it++;
779 :
780 0 : if (vmi_uuid_.is_nil() == false && vmi_uuid != vmi_uuid_) {
781 0 : continue;
782 : }
783 :
784 0 : SandeshVmiToVmVnInfo info;
785 0 : info.set_vmi_uuid(UuidToString(vmi_uuid));
786 0 : info.set_vm_uuid(UuidToString(vm_uuid));
787 0 : info.set_vn_uuid(UuidToString(vn_uuid));
788 0 : if (vmi_entry->sub_interface_)
789 0 : info.set_sub_interface("True");
790 : else
791 0 : info.set_sub_interface("False");
792 0 : info.set_vlan_tag(vmi_entry->vlan_tag_);
793 0 : info.set_parent_uuid(UuidToString(vmi_entry->parent_vmi_));
794 0 : info.set_mac(vmi_entry->mac_);
795 0 : port_list.push_back(info);
796 0 : }
797 0 : resp->set_port_list(port_list);
798 :
799 0 : resp->set_context(context_);
800 0 : resp->set_more(false);
801 0 : resp->Response();
802 0 : return true;
803 0 : }
804 :
805 0 : void FetchVmiToVmVnUuidReq::HandleRequest() const {
806 0 : Agent *agent = Agent::GetInstance();
807 0 : boost::uuids::uuid u = StringToUuid(get_vmi_uuid());
808 0 : agent->task_scheduler()->Enqueue(new SandeshVmiToVmVnTask(agent, context(),
809 0 : u));
810 0 : }
811 :
812 : // vmvn_to_vmi_tree_ routes
813 : class SandeshVmVnToVmiTask : public SandeshPortSubscribeTask {
814 : public:
815 0 : SandeshVmVnToVmiTask(Agent *agent, const std::string &context,
816 : const boost::uuids::uuid &vm_uuid,
817 0 : const boost::uuids::uuid &vn_uuid) :
818 : SandeshPortSubscribeTask(agent, context),
819 0 : vm_uuid_(vm_uuid), vn_uuid_(vn_uuid) {
820 0 : }
821 0 : virtual ~SandeshVmVnToVmiTask() { }
822 :
823 : virtual bool Run();
824 0 : std::string Description() const { return "SandeshVmVnToVmiTask"; }
825 : private:
826 : boost::uuids::uuid vm_uuid_;
827 : boost::uuids::uuid vn_uuid_;
828 : DISALLOW_COPY_AND_ASSIGN(SandeshVmVnToVmiTask);
829 : };
830 :
831 0 : bool SandeshVmVnToVmiTask::Run() {
832 0 : SandeshVmVnToVmiResp *resp = new SandeshVmVnToVmiResp();
833 :
834 : PortSubscribeTable::VmVnToVmiTree::const_iterator it =
835 0 : table_->vmvn_to_vmi_tree_.begin();
836 0 : std::vector<SandeshVmVnToVmiInfo> port_list;
837 0 : while (it != table_->vmvn_to_vmi_tree_.end()) {
838 0 : boost::uuids::uuid vm_uuid = it->first.vm_uuid_;
839 0 : boost::uuids::uuid vn_uuid = it->first.vn_uuid_;
840 0 : boost::uuids::uuid vmi_uuid = it->second;
841 0 : it++;
842 :
843 0 : if (vm_uuid_.is_nil() == false && vm_uuid != vm_uuid_) {
844 0 : continue;
845 : }
846 :
847 0 : if (vn_uuid_.is_nil() == false && vn_uuid != vn_uuid_) {
848 0 : continue;
849 : }
850 :
851 0 : SandeshVmVnToVmiInfo info;
852 0 : info.set_vmi_uuid(UuidToString(vmi_uuid));
853 0 : info.set_vm_uuid(UuidToString(vm_uuid));
854 0 : info.set_vn_uuid(UuidToString(vn_uuid));
855 0 : port_list.push_back(info);
856 0 : }
857 0 : resp->set_port_list(port_list);
858 :
859 0 : resp->set_context(context_);
860 0 : resp->set_more(false);
861 0 : resp->Response();
862 0 : return true;
863 0 : }
864 :
865 0 : void FetchVmVnToVmiUuidReq::HandleRequest() const {
866 0 : Agent *agent = Agent::GetInstance();
867 0 : boost::uuids::uuid u1 = StringToUuid(get_vm_uuid());
868 0 : boost::uuids::uuid u2 = StringToUuid(get_vn_uuid());
869 0 : agent->task_scheduler()->Enqueue(new SandeshVmVnToVmiTask(agent, context(),
870 0 : u1, u2));
871 0 : }
|