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