Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "ifmap/ifmap_server_table.h"
6 :
7 : #include <boost/algorithm/string.hpp>
8 : #include <boost/checked_delete.hpp>
9 : #include <boost/type_traits.hpp>
10 :
11 : #include "base/compiler.h"
12 : #include "base/logging.h"
13 : #include "db/db.h"
14 : #include "db/db_graph.h"
15 : #include "db/db_table_partition.h"
16 : #include "ifmap/ifmap_link.h"
17 : #include "ifmap/ifmap_link_table.h"
18 : #include "ifmap/ifmap_log.h"
19 : #include "ifmap/ifmap_log_types.h"
20 :
21 : using namespace std;
22 :
23 170567 : IFMapServerTable::RequestData::RequestData() {
24 170567 : }
25 :
26 8024 : IFMapServerTable::RequestData::RequestData(IFMapOrigin::Origin orig,
27 8024 : const string &type, const string &name)
28 8024 : : origin(orig), id_type(type), id_name(name) {
29 8022 : }
30 :
31 : // Warning: std::unique_ptr<> will not call the destructor if the type is
32 : // incomplete at the time the unique_ptr destructor is generated. Depending
33 : // on the compiler this may occur at different times. With clang the
34 : // unique_ptr appears to be generated when needed by an enclosing type.
35 : // gcc appears to behave differently.
36 357182 : IFMapServerTable::RequestData::~RequestData() {
37 : #if defined(__GNUC__)
38 : #if (__GNUC_PREREQ(4, 2) > 0)
39 : boost::has_virtual_destructor<AutogenProperty>::type has_destructor;
40 178591 : assert(has_destructor);
41 : #endif
42 : #endif
43 178591 : boost::checked_delete(content.release());
44 357182 : }
45 :
46 :
47 1224488 : IFMapServerTable::IFMapServerTable(DB *db, const string &name, DBGraph *graph)
48 1224488 : : IFMapTable(db, name, graph) {
49 1224488 : }
50 :
51 654359 : unique_ptr<DBEntry> IFMapServerTable::AllocEntry(const DBRequestKey *key) const {
52 : unique_ptr<DBEntry> entry(
53 654359 : new IFMapNode(const_cast<IFMapServerTable *>(this)));
54 654359 : entry->SetKey(key);
55 654359 : return entry;
56 0 : }
57 :
58 246534 : static IFMapServerTable *TableFind(DB *db, const string &metadata) {
59 246534 : string name = metadata;
60 246534 : std::replace(name.begin(), name.end(), '-', '_');
61 246534 : name = "__ifmap__." + name + ".0";
62 : IFMapServerTable *table =
63 246534 : static_cast<IFMapServerTable *>(db->FindTable(name));
64 246534 : return table;
65 246534 : }
66 :
67 58913 : IFMapNode *IFMapServerTable::EntryLookup(RequestKey *request) {
68 58913 : unique_ptr<DBEntry> key(AllocEntry(request));
69 58913 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
70 58913 : if ((node == NULL) || node->IsDeleted()) {
71 111 : return NULL;
72 : }
73 58802 : return node;
74 58913 : }
75 :
76 322912 : IFMapNode *IFMapServerTable::EntryLocate(RequestKey *request, bool *changep) {
77 322912 : unique_ptr<DBEntry> key(AllocEntry(request));
78 322912 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
79 322912 : if (node != NULL) {
80 133789 : if (node->IsDeleted()) {
81 4 : node->ClearDelete();
82 4 : graph()->AddNode(node);
83 4 : IFMAP_DEBUG(IFMapNodeOperation, "Re-creating", node->ToString());
84 4 : *changep = true;
85 : }
86 133789 : return node;
87 : }
88 189123 : *changep = true;
89 : node = const_cast<IFMapNode *>(
90 189123 : static_cast<const IFMapNode *>(key.release()));
91 : DBTablePartition *partition =
92 189123 : static_cast<DBTablePartition *>(GetTablePartition(0));
93 189123 : partition->Add(node);
94 189123 : graph()->AddNode(node);
95 189123 : IFMAP_DEBUG(IFMapNodeOperation, "Creating", node->ToString());
96 189123 : return node;
97 322912 : }
98 :
99 33374 : IFMapNode *IFMapServerTable::TableEntryLookup(IFMapServerTable *table,
100 : const string &id_name) {
101 33374 : RequestKey request;
102 33374 : request.id_name = id_name;
103 66748 : return table->EntryLookup(&request);
104 33374 : }
105 :
106 169764 : IFMapNode *IFMapServerTable::TableEntryLocate(IFMapServerTable *table,
107 : const string &id_name,
108 : bool *changep) {
109 169764 : RequestKey request;
110 169764 : request.id_name = id_name;
111 339528 : return table->EntryLocate(&request, changep);
112 169764 : }
113 :
114 203136 : IFMapLink *IFMapServerTable::FindLinkNode(IFMapNode *first, IFMapNode *second,
115 : const string &metadata) {
116 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
117 203136 : database()->FindTable("__ifmap_metadata__.0"));
118 203136 : assert(table != NULL);
119 203136 : IFMapLink *link = table->FindLink(metadata, first, second);
120 203136 : return (link ? (link->IsDeleted() ? NULL : link) : NULL);
121 : }
122 :
123 159860 : IFMapLink *IFMapServerTable::LinkNodeAdd(IFMapNode *first, IFMapNode *second,
124 : const string &metadata,
125 : uint64_t sequence_number,
126 : const IFMapOrigin &origin) {
127 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
128 159860 : database()->FindTable("__ifmap_metadata__.0"));
129 159860 : assert(table != NULL);
130 159860 : IFMAP_DEBUG(IFMapLinkOperation, "Creating", metadata);
131 159860 : return table->AddLink(first, second, metadata, sequence_number, origin);
132 : }
133 :
134 9952 : void IFMapServerTable::LinkNodeUpdate(IFMapLink *link, uint64_t sequence_number,
135 : const IFMapOrigin &origin) {
136 9952 : link->set_last_change_at_to_now();
137 9952 : link->UpdateProperties(origin, sequence_number);
138 9952 : }
139 :
140 33317 : void IFMapServerTable::LinkNodeDelete(IFMapLink *link,
141 : const IFMapOrigin &origin) {
142 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
143 33317 : database()->FindTable("__ifmap_metadata__.0"));
144 33317 : assert(table != NULL);
145 33317 : IFMAP_DEBUG(IFMapLinkOperation, "Deleting", link->ToString());
146 33317 : table->DeleteLink(link, origin);
147 33317 : }
148 :
149 : // Generate an unique key for a Link Attribute element. The generated key should
150 : // be independent of the order in which the parameters are specified.
151 79896 : std::string IFMapServerTable::LinkAttrKey(IFMapNode *first, IFMapNode *second) {
152 79896 : ostringstream oss;
153 79896 : oss << "attr(";
154 79896 : if (first->IsLess(*second)) {
155 67401 : oss << first->name() << "," << second->name();
156 : } else {
157 12495 : oss << second->name() << "," << first->name();
158 : }
159 79896 : oss << ")";
160 159792 : return oss.str();
161 79896 : }
162 :
163 41801 : void IFMapServerTable::DeleteNode(IFMapNode *node) {
164 41801 : IFMAP_DEBUG(IFMapNodeOperation, "Deleting", node->ToString());
165 : DBTablePartition *partition =
166 41801 : static_cast<DBTablePartition *>(GetTablePartition(0));
167 41801 : graph()->RemoveNode(node);
168 41801 : partition->Delete(node);
169 41801 : }
170 :
171 120788 : void IFMapServerTable::Notify(IFMapNode *node) {
172 : DBTablePartition *partition =
173 120788 : static_cast<DBTablePartition *>(GetTablePartition(0));
174 120788 : partition->Change(node);
175 120788 : }
176 :
177 58636 : bool IFMapServerTable::DeleteIfEmpty(IFMapNode *node) {
178 58636 : if ((node->GetObject() == NULL) && !node->HasAdjacencies(graph())) {
179 41801 : DeleteNode(node);
180 41801 : return true;
181 : }
182 16835 : return false;
183 : }
184 :
185 114558 : IFMapObject *IFMapServerTable::LocateObject(IFMapNode *node,
186 : IFMapOrigin origin) {
187 114558 : IFMapObject *object = node->Find(origin);
188 114558 : if (object == NULL) {
189 99098 : object = AllocObject();
190 99098 : object->set_origin(origin);
191 99098 : node->Insert(object);
192 : }
193 114558 : return object;
194 : }
195 :
196 49023 : IFMapIdentifier *IFMapServerTable::LocateIdentifier(IFMapNode *node,
197 : IFMapOrigin origin,
198 : uint64_t sequence_number) {
199 49023 : IFMapObject *object = LocateObject(node, origin);
200 49023 : assert(object);
201 :
202 : // If the sequence number has changed, we are processing updates in a new
203 : // connection to the ifmap server. Save the current properties and check
204 : // later with the updated properties to find any stale ones.
205 49023 : if (object->sequence_number() != sequence_number) {
206 16 : IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(object);
207 16 : identifier->TransferPropertyToOldProperty();
208 16 : object->set_sequence_number(sequence_number);
209 : }
210 49023 : return static_cast<IFMapIdentifier *>(object);
211 : }
212 :
213 65535 : IFMapLinkAttr *IFMapServerTable::LocateLinkAttr(IFMapNode *node,
214 : IFMapOrigin origin,
215 : uint64_t sequence_number) {
216 65535 : IFMapObject *object = LocateObject(node, origin);
217 65535 : assert(object);
218 65535 : object->set_sequence_number(sequence_number);
219 :
220 65535 : return static_cast<IFMapLinkAttr *>(object);
221 : }
222 :
223 178583 : void IFMapServerTable::Input(DBTablePartition *partition, DBClient *client,
224 : DBRequest *request) {
225 178583 : assert(request->oper == DBRequest::DB_ENTRY_ADD_CHANGE ||
226 : request->oper == DBRequest::DB_ENTRY_DELETE);
227 178583 : RequestKey *key = static_cast<RequestKey *>(request->key.get());
228 178583 : RequestData *data = static_cast<RequestData *>(request->data.get());
229 178583 : assert(data != NULL);
230 :
231 178583 : IFMapServerTable *rtable = NULL;
232 178583 : IFMapServerTable *mtable = NULL;
233 :
234 : // Sanity checks before allocation resources.
235 178583 : if (!data->id_name.empty()) {
236 123267 : rtable = TableFind(database(), data->id_type);
237 123267 : if (!rtable) {
238 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
239 : data->id_type);
240 55377 : return;
241 : }
242 123267 : mtable = TableFind(database(), data->metadata);
243 161961 : if (mtable == NULL && request->oper == DBRequest::DB_ENTRY_ADD_CHANGE &&
244 38694 : data->content.get() != NULL) {
245 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
246 : data->metadata);
247 0 : return;
248 : }
249 : }
250 :
251 178583 : IFMapNode *first = NULL;
252 178583 : bool lchanged = false;
253 178583 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
254 25435 : first = EntryLookup(key);
255 25435 : if (first == NULL) {
256 74 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
257 : key->id_name);
258 74 : return;
259 : }
260 : } else {
261 153148 : first = EntryLocate(key, &lchanged);
262 : }
263 :
264 178509 : if (data->id_name.empty()) {
265 : // property
266 55266 : first->set_last_change_at_to_now();
267 55266 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
268 48919 : IFMapIdentifier *identifier = LocateIdentifier(first, data->origin,
269 : key->id_seq_num);
270 48919 : identifier->SetProperty(data->metadata, data->content.get());
271 48919 : partition->Change(first);
272 : } else {
273 : IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(
274 6347 : first->Find(data->origin));
275 6347 : if (identifier == NULL) {
276 8 : return;
277 : }
278 6339 : identifier->ClearProperty(data->metadata);
279 : // Figure out whether to delete the identifier.
280 6339 : if (identifier->empty()) {
281 5253 : first->Remove(identifier);
282 : }
283 6339 : if (DeleteIfEmpty(first) == false) {
284 5875 : partition->Change(first);
285 : }
286 : }
287 55258 : return;
288 : }
289 :
290 123243 : IFMapNode *second = NULL;
291 123243 : bool rchanged = false;
292 123243 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
293 19014 : second = TableEntryLookup(rtable, data->id_name);
294 19014 : if (second == NULL) {
295 14 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
296 : data->id_name);
297 14 : return;
298 : }
299 : } else {
300 104229 : second = TableEntryLocate(rtable, data->id_name, &rchanged);
301 : }
302 :
303 123229 : IFMapNode *midnode = NULL;
304 123229 : bool mchanged = false;
305 :
306 123229 : if (mtable != NULL) {
307 : // link with attribute
308 79895 : string id_mid = LinkAttrKey(first, second);
309 79895 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
310 14360 : midnode = TableEntryLookup(mtable, id_mid);
311 14360 : if (midnode == NULL) {
312 23 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
313 : id_mid);
314 23 : return;
315 : }
316 : } else {
317 65535 : midnode = TableEntryLocate(mtable, id_mid, &mchanged);
318 : }
319 79872 : midnode->set_last_change_at_to_now();
320 79872 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
321 : IFMapLink *glink =
322 131070 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
323 65535 : data->metadata));
324 65535 : if (glink == NULL) {
325 125518 : glink = LinkNodeAdd(first, midnode, data->metadata,
326 62759 : key->id_seq_num, data->origin);
327 62759 : graph()->Link(first, midnode, glink);
328 : } else {
329 2776 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
330 : }
331 131070 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
332 65535 : data->metadata));
333 65535 : if (glink == NULL) {
334 125514 : glink = LinkNodeAdd(midnode, second, data->metadata,
335 62757 : key->id_seq_num, data->origin);
336 62757 : graph()->Link(midnode, second, glink);
337 : } else {
338 2778 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
339 : }
340 65535 : IFMapLinkAttr *link_attr = mtable->LocateLinkAttr(midnode,
341 : data->origin,
342 : key->id_seq_num);
343 65535 : mchanged |= link_attr->SetData(data->content.get());
344 : } else {
345 14337 : IFMapObject *object = midnode->Find(data->origin);
346 14337 : if (object == NULL) {
347 0 : return;
348 : }
349 14337 : midnode->Remove(object);
350 14337 : if (midnode->GetObject() != NULL) {
351 0 : return;
352 : }
353 14337 : IFMapOrigin origin(data->origin);
354 : IFMapLink *glink =
355 28674 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
356 14337 : data->metadata));
357 14337 : if (glink) LinkNodeDelete(glink, origin);
358 28674 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
359 14337 : data->metadata));
360 14337 : if (glink) LinkNodeDelete(glink, origin);
361 14337 : DeleteIfEmpty(first);
362 14337 : rtable->DeleteIfEmpty(second);
363 14337 : mtable->DeleteIfEmpty(midnode);
364 : }
365 79895 : } else {
366 : // link
367 43334 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
368 : // Link is added if not present
369 : IFMapLink *glink =
370 77388 : static_cast<IFMapLink *>(FindLinkNode(first, second,
371 38694 : data->metadata));
372 38694 : if (glink == NULL) {
373 68592 : glink = LinkNodeAdd(first, second, data->metadata,
374 34296 : key->id_seq_num, data->origin);
375 34296 : graph()->Link(first, second, glink);
376 : } else {
377 4398 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
378 : }
379 : } else {
380 : // TODO: check if the edge is present and ignore otherwise.
381 4640 : IFMapLink *glink = FindLinkNode(first, second, data->metadata);
382 4640 : if (glink != NULL) {
383 4637 : IFMapOrigin origin(data->origin);
384 4637 : LinkNodeDelete(glink, origin);
385 : // check whether any of the identifiers can be deleted.
386 4637 : DeleteIfEmpty(first);
387 4637 : rtable->DeleteIfEmpty(second);
388 : }
389 : }
390 : }
391 :
392 123206 : if (lchanged) {
393 48437 : partition->Change(first);
394 : }
395 123206 : if (rchanged) {
396 55641 : rtable->Notify(second);
397 : }
398 123206 : if (mchanged) {
399 65147 : mtable->Notify(midnode);
400 : }
401 : }
402 :
403 1221768 : void IFMapServerTable::Clear() {
404 : DBTablePartition *partition = static_cast<DBTablePartition *>(
405 1221768 : GetTablePartition(0));
406 1221768 : assert(!HasListeners());
407 1221768 : for (IFMapNode *node = static_cast<IFMapNode *>(partition->GetFirst()),
408 1221768 : *next = NULL;
409 1369094 : node != NULL; node = next) {
410 147326 : next = static_cast<IFMapNode *>(partition->GetNext(node));
411 147326 : if (node->IsDeleted()) {
412 0 : continue;
413 : }
414 147326 : graph()->RemoveNode(node);
415 147326 : partition->Delete(node);
416 : }
417 1221768 : }
418 :
419 : // This is called in the context of the virtual_router table i.e. 'this' points
420 : // to __ifmap__.virtual_router.0
421 52 : void IFMapServerTable::IFMapVmSubscribe(const std::string &vr_name,
422 : const std::string &vm_name,
423 : bool subscribe, bool has_vms) {
424 52 : if (subscribe) {
425 52 : IFMapProcVmSubscribe(vr_name, vm_name);
426 : } else {
427 0 : IFMapProcVmUnsubscribe(vr_name, vm_name, has_vms);
428 : }
429 52 : }
430 :
431 52 : void IFMapServerTable::IFMapAddVrVmLink(IFMapNode *vr_node,
432 : IFMapNode *vm_node) {
433 : // Add the link if it does not exist. If it does, add XMPP as origin
434 52 : uint64_t sequence_number = 0;
435 52 : IFMapOrigin origin(IFMapOrigin::XMPP);
436 :
437 52 : std::string metadata = std::string("virtual-router-virtual-machine");
438 : IFMapLink *glink =
439 52 : static_cast<IFMapLink *>(FindLinkNode(vr_node, vm_node, metadata));
440 52 : if (glink == NULL) {
441 48 : glink = LinkNodeAdd(vr_node, vm_node, metadata, sequence_number, origin);
442 48 : graph()->Link(vr_node, vm_node, glink);
443 : } else {
444 4 : glink->AddOriginInfo(origin, sequence_number);
445 : }
446 52 : }
447 :
448 : // Process the vm-subscribe only after a config-add of the vm
449 52 : void IFMapServerTable::IFMapProcVmSubscribe(const std::string &vr_name,
450 : const std::string &vm_name) {
451 52 : bool changed = false;
452 :
453 : // Lookup the node corresponding to vr_name
454 52 : RequestKey request;
455 52 : request.id_name = vr_name;
456 52 : IFMapNode *vr_node = EntryLookup(&request);
457 52 : if (vr_node == NULL) {
458 0 : vr_node = EntryLocate(&request, &changed);
459 : }
460 52 : LocateIdentifier(vr_node, IFMapOrigin(IFMapOrigin::XMPP), 0);
461 :
462 : // Lookup the node corresponding to vm_name
463 : IFMapServerTable *vm_table = static_cast<IFMapServerTable *>(
464 52 : database()->FindTable("__ifmap__.virtual_machine.0"));
465 52 : assert(vm_table != NULL);
466 52 : request.id_name = vm_name;
467 52 : IFMapNode *vm_node = vm_table->EntryLookup(&request);
468 52 : assert(vm_node != NULL);
469 52 : vm_table->LocateIdentifier(vm_node, IFMapOrigin(IFMapOrigin::XMPP), 0);
470 :
471 52 : IFMapAddVrVmLink(vr_node, vm_node);
472 52 : }
473 :
474 6 : void IFMapServerTable::IFMapRemoveVrVmLink(IFMapNode *vr_node,
475 : IFMapNode *vm_node) {
476 : // Remove XMPP as origin. If there are no more origin's, delete the link.
477 6 : IFMapOrigin origin(IFMapOrigin::XMPP);
478 6 : std::string metadata = std::string("virtual-router-virtual-machine");
479 : IFMapLink *glink =
480 6 : static_cast<IFMapLink *>(FindLinkNode(vr_node, vm_node, metadata));
481 6 : LinkNodeDelete(glink, origin);
482 6 : }
483 :
484 0 : void IFMapServerTable::IFMapProcVmUnsubscribe(const std::string &vr_name,
485 : const std::string &vm_name,
486 : bool has_vms) {
487 : // Lookup the node corresponding to vr_name
488 0 : RequestKey request;
489 0 : request.id_name = vr_name;
490 0 : IFMapNode *vr_node = EntryLookup(&request);
491 0 : assert(vr_node != NULL);
492 :
493 : // Lookup the node corresponding to vm_name
494 : IFMapServerTable *vm_table = static_cast<IFMapServerTable *>(
495 0 : database()->FindTable("__ifmap__.virtual_machine.0"));
496 0 : assert(vm_table != NULL);
497 0 : request.id_name = vm_name;
498 0 : IFMapNode *vm_node = vm_table->EntryLookup(&request);
499 0 : assert(vm_node != NULL);
500 :
501 0 : IFMapRemoveVrVmLink(vr_node, vm_node);
502 :
503 0 : IFMapOrigin origin(IFMapOrigin::XMPP);
504 0 : RemoveObjectAndDeleteNode(vm_node, origin);
505 :
506 : // Remove XMPP as origin from the VR only if all the VMs are gone
507 0 : if (!has_vms) {
508 0 : RemoveObjectAndDeleteNode(vr_node, origin);
509 : }
510 0 : }
511 :
512 12 : void IFMapServerTable::RemoveObjectAndDeleteNode(IFMapNode *node,
513 : const IFMapOrigin &origin) {
514 12 : IFMapServerTable *table = static_cast<IFMapServerTable *>(node->table());
515 12 : assert(table);
516 12 : IFMapObject *object = node->Find(origin);
517 12 : if (object) {
518 0 : node->Remove(object);
519 : }
520 12 : table->DeleteIfEmpty(node);
521 12 : }
522 :
|