Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <oper/interface_common.h>
7 : #include <uve/vm_uve_table_base.h>
8 : #include <uve/agent_uve_base.h>
9 :
10 : using boost::uuids::nil_uuid;
11 :
12 4 : VmUveTableBase::VmUveTableBase(Agent *agent, uint32_t default_intvl)
13 4 : : uve_vm_map_(), agent_(agent), uve_vm_map_mutex_(),
14 4 : intf_listener_id_(DBTableBase::kInvalidId),
15 4 : vm_listener_id_(DBTableBase::kInvalidId), timer_last_visited_(nil_uuid()),
16 4 : timer_(TimerManager::CreateTimer
17 4 : (*(agent->event_manager())->io_service(),
18 : "VmUveTimer",
19 4 : TaskScheduler::GetInstance()->GetTaskId(kTaskDBExclude), 0)) {
20 4 : expiry_time_ = default_intvl;
21 4 : timer_->Start(expiry_time_,
22 : boost::bind(&VmUveTableBase::TimerExpiry, this));
23 4 : }
24 :
25 4 : VmUveTableBase::~VmUveTableBase() {
26 4 : }
27 :
28 0 : bool VmUveTableBase::TimerExpiry() {
29 0 : UveVmMap::iterator it = uve_vm_map_.lower_bound(timer_last_visited_);
30 0 : if (it == uve_vm_map_.end()) {
31 0 : timer_last_visited_ = nil_uuid();
32 0 : return true;
33 : }
34 :
35 0 : uint32_t count = 0;
36 0 : while (it != uve_vm_map_.end() && count < AgentUveBase::kUveCountPerTimer) {
37 0 : VmUveEntryBase* entry = it->second.get();
38 0 : const boost::uuids::uuid u= it->first;
39 0 : UveVmMap::iterator prev = it;
40 0 : it++;
41 0 : count++;
42 :
43 0 : if (entry->deleted()) {
44 0 : SendVmDeleteMsg(entry->vm_config_name());
45 0 : if (!entry->renewed()) {
46 0 : std::scoped_lock lock(uve_vm_map_mutex_);
47 0 : uve_vm_map_.erase(prev);
48 0 : } else {
49 0 : entry->set_deleted(false);
50 0 : entry->set_renewed(false);
51 0 : entry->set_changed(false);
52 0 : SendVmMsg(entry, u);
53 : }
54 0 : } else if (entry->changed()) {
55 0 : SendVmMsg(entry, u);
56 0 : entry->set_changed(false);
57 : /* Clear renew flag to be on safer side. Not really required */
58 0 : entry->set_renewed(false);
59 : }
60 : }
61 :
62 0 : if (it == uve_vm_map_.end()) {
63 0 : timer_last_visited_ = nil_uuid();
64 0 : set_expiry_time(agent_->uve()->default_interval());
65 : } else {
66 0 : timer_last_visited_ = it->first;
67 0 : set_expiry_time(agent_->uve()->incremental_interval());
68 : }
69 : /* Return true to trigger auto-restart of timer */
70 0 : return true;
71 : }
72 :
73 0 : void VmUveTableBase::set_expiry_time(int time) {
74 0 : if (time != expiry_time_) {
75 0 : expiry_time_ = time;
76 0 : timer_->Reschedule(expiry_time_);
77 : }
78 0 : }
79 :
80 0 : void VmUveTableBase::SendVmDeleteMsg(const string &vm_config_name) {
81 0 : UveVirtualMachineAgent uve;
82 0 : uve.set_name(vm_config_name);
83 0 : uve.set_deleted(true);
84 0 : DispatchVmMsg(uve);
85 0 : }
86 :
87 332 : VmUveEntryBase* VmUveTableBase::Add(const VmEntry *vm, bool vm_notify) {
88 332 : VmUveEntryPtr uve = Allocate(vm);
89 332 : pair<UveVmMap::iterator, bool> ret;
90 332 : ret = uve_vm_map_.insert(UveVmPair(vm->GetUuid(), uve));
91 332 : UveVmMap::iterator it = ret.first;
92 332 : VmUveEntryBase* entry = it->second.get();
93 332 : if (!entry->add_by_vm_notify()) {
94 165 : entry->set_add_by_vm_notify(vm_notify);
95 : }
96 332 : if (entry->deleted()) {
97 300 : entry->set_renewed(true);
98 : }
99 332 : return entry;
100 332 : }
101 :
102 165 : void VmUveTableBase::Delete(const boost::uuids::uuid &u) {
103 165 : UveVmMap::iterator it = uve_vm_map_.find(u);
104 165 : if (it == uve_vm_map_.end()) {
105 0 : return;
106 : }
107 165 : VmUveEntryBase* entry = it->second.get();
108 : /* We need to reset all non-key fields to ensure that they have right
109 : * values since the entry is getting re-used. Also update the 'deleted_'
110 : * and 'renewed_' flags */
111 165 : entry->Reset();
112 165 : return;
113 : }
114 :
115 0 : void VmUveTableBase::Change(const VmEntry *vm) {
116 0 : VmUveEntryBase* entry = UveEntryFromVm(vm->GetUuid());
117 0 : if (entry == NULL) {
118 0 : return;
119 : }
120 :
121 0 : bool send = entry->Update(vm);
122 0 : if (send) {
123 0 : entry->set_changed(true);
124 : }
125 : }
126 :
127 0 : VmUveTableBase::VmUveEntryPtr VmUveTableBase::Allocate(const VmEntry *vm) {
128 0 : VmUveEntryPtr uve(new VmUveEntryBase(agent_, vm->GetCfgName()));
129 0 : return uve;
130 : }
131 :
132 332 : VmUveEntryBase* VmUveTableBase::UveEntryFromVm(const boost::uuids::uuid &u) {
133 332 : UveVmMap::iterator it = uve_vm_map_.find(u);
134 332 : if (it == uve_vm_map_.end()) {
135 0 : return NULL;
136 : }
137 332 : return it->second.get();
138 : }
139 :
140 0 : void VmUveTableBase::DispatchVmMsg(const UveVirtualMachineAgent &uve) {
141 0 : UveVirtualMachineAgentTrace::Send(uve);
142 0 : }
143 :
144 0 : void VmUveTableBase::SendVmMsg(VmUveEntryBase *entry,
145 : const boost::uuids::uuid &u) {
146 0 : UveVirtualMachineAgent uve;
147 0 : if (entry->FrameVmMsg(u, &uve)) {
148 0 : DispatchVmMsg(uve);
149 : }
150 0 : }
151 :
152 165 : void VmUveTableBase::MarkChanged(const boost::uuids::uuid &u) {
153 165 : VmUveEntryBase* entry = UveEntryFromVm(u);
154 165 : if (entry == NULL) {
155 0 : return;
156 : }
157 165 : entry->set_changed(true);
158 165 : return;
159 : }
160 :
161 167 : void VmUveTableBase::InterfaceAddHandler(const VmEntry* vm,
162 : const VmInterface *vmi) {
163 167 : VmUveEntryBase *vm_uve_entry = Add(vm, false);
164 :
165 167 : vm_uve_entry->InterfaceAdd(vmi->cfg_name());
166 167 : vm_uve_entry->set_vm_name(vmi->vm_name());
167 167 : vm_uve_entry->set_changed(true);
168 167 : }
169 :
170 167 : void VmUveTableBase::InterfaceDeleteHandler(const boost::uuids::uuid &u,
171 : const string &intf_cfg_name) {
172 167 : VmUveEntryBase* entry = UveEntryFromVm(u);
173 167 : if (entry == NULL) {
174 0 : return;
175 : }
176 :
177 167 : entry->InterfaceDelete(intf_cfg_name);
178 167 : entry->set_changed(true);
179 : }
180 :
181 0 : void VmUveTableBase::UpdateVmName(const boost::uuids::uuid &u,
182 : const string &vm_name) {
183 0 : VmUveEntryBase* entry = UveEntryFromVm(u);
184 0 : if (entry == NULL) {
185 0 : return;
186 : }
187 :
188 0 : entry->set_vm_name(vm_name);
189 0 : entry->set_changed(true);
190 : }
191 :
192 1421 : void VmUveTableBase::InterfaceNotify(DBTablePartBase *partition,
193 : DBEntryBase *e) {
194 1421 : const VmInterface *vm_port = dynamic_cast<const VmInterface*>(e);
195 1421 : if (vm_port == NULL) {
196 21 : return;
197 : }
198 :
199 : VmUveInterfaceState *state = static_cast<VmUveInterfaceState *>
200 1400 : (e->GetState(partition->parent(), intf_listener_id_));
201 1400 : if (e->IsDeleted() || ((vm_port->vm() == NULL))) {
202 416 : if (state) {
203 167 : InterfaceDeleteHandler(state->vm_uuid_, state->interface_cfg_name_);
204 167 : e->ClearState(partition->parent(), intf_listener_id_);
205 167 : delete state;
206 : }
207 : } else {
208 984 : const VmEntry *vm = vm_port->vm();
209 984 : VmInterface::FloatingIpSet old_list;
210 :
211 984 : if (!state) {
212 : /* Skip Add notification if it does not have config name */
213 167 : if (vm_port->cfg_name().empty()) {
214 0 : return;
215 : }
216 167 : state = new VmUveInterfaceState(nil_uuid(), "");
217 167 : e->SetState(partition->parent(), intf_listener_id_, state);
218 : }
219 : /* Handle Change of VM in a given VM interface */
220 1801 : if ((vm->GetUuid() != state->vm_uuid_) ||
221 817 : (vm_port->cfg_name() != state->interface_cfg_name_)) {
222 : //Handle disassociation of old VM from the VMI
223 167 : if (state->vm_uuid_ != nil_uuid() &&
224 0 : !state->interface_cfg_name_.empty()) {
225 0 : InterfaceDeleteHandler(state->vm_uuid_,
226 0 : state->interface_cfg_name_);
227 : }
228 334 : if (vm->GetUuid() != nil_uuid() &&
229 167 : !vm_port->cfg_name().empty()) {
230 167 : InterfaceAddHandler(vm, vm_port);
231 : }
232 167 : state->vm_uuid_ = vm->GetUuid();
233 167 : state->interface_cfg_name_ = vm_port->cfg_name();
234 167 : state->vm_name_ = vm_port->vm_name();
235 817 : } else if (vm_port->vm_name() != state->vm_name_) {
236 0 : UpdateVmName(state->vm_uuid_, vm_port->vm_name());
237 0 : state->vm_name_ = vm_port->vm_name();
238 : }
239 984 : }
240 : }
241 :
242 330 : void VmUveTableBase::VmNotify(DBTablePartBase *partition, DBEntryBase *e) {
243 330 : const VmEntry *vm = static_cast<const VmEntry *>(e);
244 :
245 : VmUveVmState *state = static_cast<VmUveVmState *>
246 330 : (e->GetState(partition->parent(), vm_listener_id_));
247 :
248 330 : if (e->IsDeleted()) {
249 165 : if (state) {
250 165 : Delete(vm->GetUuid());
251 :
252 165 : VmStatCollectionStop(state);
253 :
254 165 : e->ClearState(partition->parent(), vm_listener_id_);
255 165 : delete state;
256 : }
257 165 : return;
258 : }
259 :
260 165 : if (!state) {
261 165 : state = new VmUveVmState();
262 165 : e->SetState(partition->parent(), vm_listener_id_, state);
263 :
264 165 : Add(vm, true);
265 :
266 165 : VmStatCollectionStart(state, vm);
267 165 : MarkChanged(vm->GetUuid());
268 : } else {
269 0 : Change(vm);
270 : }
271 : }
272 :
273 0 : void VmUveTableBase::VmStatCollectionStart(VmUveVmState *state,
274 : const VmEntry *vm) {
275 0 : }
276 :
277 0 : void VmUveTableBase::VmStatCollectionStop(VmUveVmState *state) {
278 0 : }
279 :
280 2 : void VmUveTableBase::RegisterDBClients() {
281 2 : InterfaceTable *intf_table = agent_->interface_table();
282 2 : intf_listener_id_ = intf_table->Register
283 2 : (boost::bind(&VmUveTableBase::InterfaceNotify, this, _1, _2));
284 :
285 2 : VmTable *vm_table = agent_->vm_table();
286 2 : vm_listener_id_ = vm_table->Register
287 2 : (boost::bind(&VmUveTableBase::VmNotify, this, _1, _2));
288 2 : }
289 :
290 4 : void VmUveTableBase::Shutdown(void) {
291 4 : if (vm_listener_id_ != DBTableBase::kInvalidId)
292 2 : agent_->vm_table()->Unregister(vm_listener_id_);
293 4 : if (intf_listener_id_ != DBTableBase::kInvalidId)
294 2 : agent_->interface_table()->Unregister(intf_listener_id_);
295 :
296 4 : if (timer_) {
297 4 : timer_->Cancel();
298 4 : TimerManager::DeleteTimer(timer_);
299 4 : timer_ = NULL;
300 : }
301 4 : }
|