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