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