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 170551 : IFMapServerTable::RequestData::RequestData() {
24 170551 : }
25 :
26 8036 : IFMapServerTable::RequestData::RequestData(IFMapOrigin::Origin orig,
27 8036 : const string &type, const string &name)
28 8036 : : origin(orig), id_type(type), id_name(name) {
29 8034 : }
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 357174 : IFMapServerTable::RequestData::~RequestData() {
37 : #if defined(__GNUC__)
38 : #if (__GNUC_PREREQ(4, 2) > 0)
39 : boost::has_virtual_destructor<AutogenProperty>::type has_destructor;
40 178587 : assert(has_destructor);
41 : #endif
42 : #endif
43 178587 : boost::checked_delete(content.release());
44 357174 : }
45 :
46 :
47 1224637 : IFMapServerTable::IFMapServerTable(DB *db, const string &name, DBGraph *graph)
48 1224637 : : IFMapTable(db, name, graph) {
49 1224637 : }
50 :
51 654283 : unique_ptr<DBEntry> IFMapServerTable::AllocEntry(const DBRequestKey *key) const {
52 : unique_ptr<DBEntry> entry(
53 654283 : new IFMapNode(const_cast<IFMapServerTable *>(this)));
54 654283 : entry->SetKey(key);
55 654283 : return entry;
56 0 : }
57 :
58 246498 : static IFMapServerTable *TableFind(DB *db, const string &metadata) {
59 246498 : string name = metadata;
60 246498 : std::replace(name.begin(), name.end(), '-', '_');
61 246498 : name = "__ifmap__." + name + ".0";
62 : IFMapServerTable *table =
63 246498 : static_cast<IFMapServerTable *>(db->FindTable(name));
64 246498 : return table;
65 246498 : }
66 :
67 58895 : IFMapNode *IFMapServerTable::EntryLookup(RequestKey *request) {
68 58895 : unique_ptr<DBEntry> key(AllocEntry(request));
69 58895 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
70 58895 : if ((node == NULL) || node->IsDeleted()) {
71 111 : return NULL;
72 : }
73 58784 : return node;
74 58895 : }
75 :
76 322875 : IFMapNode *IFMapServerTable::EntryLocate(RequestKey *request, bool *changep) {
77 322875 : unique_ptr<DBEntry> key(AllocEntry(request));
78 322875 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
79 322875 : if (node != NULL) {
80 133791 : 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 133791 : return node;
87 : }
88 189084 : *changep = true;
89 : node = const_cast<IFMapNode *>(
90 189084 : static_cast<const IFMapNode *>(key.release()));
91 : DBTablePartition *partition =
92 189084 : static_cast<DBTablePartition *>(GetTablePartition(0));
93 189084 : partition->Add(node);
94 189084 : graph()->AddNode(node);
95 189084 : IFMAP_DEBUG(IFMapNodeOperation, "Creating", node->ToString());
96 189084 : return node;
97 322875 : }
98 :
99 33357 : IFMapNode *IFMapServerTable::TableEntryLookup(IFMapServerTable *table,
100 : const string &id_name) {
101 33357 : RequestKey request;
102 33357 : request.id_name = id_name;
103 66714 : return table->EntryLookup(&request);
104 33357 : }
105 :
106 169730 : IFMapNode *IFMapServerTable::TableEntryLocate(IFMapServerTable *table,
107 : const string &id_name,
108 : bool *changep) {
109 169730 : RequestKey request;
110 169730 : request.id_name = id_name;
111 339460 : return table->EntryLocate(&request, changep);
112 169730 : }
113 :
114 203085 : IFMapLink *IFMapServerTable::FindLinkNode(IFMapNode *first, IFMapNode *second,
115 : const string &metadata) {
116 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
117 203085 : database()->FindTable("__ifmap_metadata__.0"));
118 203085 : assert(table != NULL);
119 203085 : IFMapLink *link = table->FindLink(metadata, first, second);
120 203085 : return (link ? (link->IsDeleted() ? NULL : link) : NULL);
121 : }
122 :
123 159826 : 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 159826 : database()->FindTable("__ifmap_metadata__.0"));
129 159826 : assert(table != NULL);
130 159826 : IFMAP_DEBUG(IFMapLinkOperation, "Creating", metadata);
131 159826 : 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 33300 : void IFMapServerTable::LinkNodeDelete(IFMapLink *link,
141 : const IFMapOrigin &origin) {
142 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
143 33300 : database()->FindTable("__ifmap_metadata__.0"));
144 33300 : assert(table != NULL);
145 33300 : IFMAP_DEBUG(IFMapLinkOperation, "Deleting", link->ToString());
146 33300 : table->DeleteLink(link, origin);
147 33300 : }
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 79863 : std::string IFMapServerTable::LinkAttrKey(IFMapNode *first, IFMapNode *second) {
152 79863 : ostringstream oss;
153 79863 : oss << "attr(";
154 79863 : if (first->IsLess(*second)) {
155 67367 : oss << first->name() << "," << second->name();
156 : } else {
157 12496 : oss << second->name() << "," << first->name();
158 : }
159 79863 : oss << ")";
160 159726 : return oss.str();
161 79863 : }
162 :
163 41779 : void IFMapServerTable::DeleteNode(IFMapNode *node) {
164 41779 : IFMAP_DEBUG(IFMapNodeOperation, "Deleting", node->ToString());
165 : DBTablePartition *partition =
166 41779 : static_cast<DBTablePartition *>(GetTablePartition(0));
167 41779 : graph()->RemoveNode(node);
168 41779 : partition->Delete(node);
169 41779 : }
170 :
171 120744 : void IFMapServerTable::Notify(IFMapNode *node) {
172 : DBTablePartition *partition =
173 120744 : static_cast<DBTablePartition *>(GetTablePartition(0));
174 120744 : partition->Change(node);
175 120744 : }
176 :
177 58618 : bool IFMapServerTable::DeleteIfEmpty(IFMapNode *node) {
178 58618 : if ((node->GetObject() == NULL) && !node->HasAdjacencies(graph())) {
179 41779 : DeleteNode(node);
180 41779 : return true;
181 : }
182 16839 : return false;
183 : }
184 :
185 114547 : IFMapObject *IFMapServerTable::LocateObject(IFMapNode *node,
186 : IFMapOrigin origin) {
187 114547 : IFMapObject *object = node->Find(origin);
188 114547 : if (object == NULL) {
189 99080 : object = AllocObject();
190 99080 : object->set_origin(origin);
191 99080 : node->Insert(object);
192 : }
193 114547 : return object;
194 : }
195 :
196 49033 : IFMapIdentifier *IFMapServerTable::LocateIdentifier(IFMapNode *node,
197 : IFMapOrigin origin,
198 : uint64_t sequence_number) {
199 49033 : IFMapObject *object = LocateObject(node, origin);
200 49033 : 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 49033 : 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 49033 : return static_cast<IFMapIdentifier *>(object);
211 : }
212 :
213 65514 : IFMapLinkAttr *IFMapServerTable::LocateLinkAttr(IFMapNode *node,
214 : IFMapOrigin origin,
215 : uint64_t sequence_number) {
216 65514 : IFMapObject *object = LocateObject(node, origin);
217 65514 : assert(object);
218 65514 : object->set_sequence_number(sequence_number);
219 :
220 65514 : return static_cast<IFMapLinkAttr *>(object);
221 : }
222 :
223 178579 : void IFMapServerTable::Input(DBTablePartition *partition, DBClient *client,
224 : DBRequest *request) {
225 178579 : assert(request->oper == DBRequest::DB_ENTRY_ADD_CHANGE ||
226 : request->oper == DBRequest::DB_ENTRY_DELETE);
227 178579 : RequestKey *key = static_cast<RequestKey *>(request->key.get());
228 178579 : RequestData *data = static_cast<RequestData *>(request->data.get());
229 178579 : assert(data != NULL);
230 :
231 178579 : IFMapServerTable *rtable = NULL;
232 178579 : IFMapServerTable *mtable = NULL;
233 :
234 : // Sanity checks before allocation resources.
235 178579 : if (!data->id_name.empty()) {
236 123249 : rtable = TableFind(database(), data->id_type);
237 123249 : if (!rtable) {
238 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
239 : data->id_type);
240 55391 : return;
241 : }
242 123249 : mtable = TableFind(database(), data->metadata);
243 161951 : if (mtable == NULL && request->oper == DBRequest::DB_ENTRY_ADD_CHANGE &&
244 38702 : data->content.get() != NULL) {
245 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
246 : data->metadata);
247 0 : return;
248 : }
249 : }
250 :
251 178579 : IFMapNode *first = NULL;
252 178579 : bool lchanged = false;
253 178579 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
254 25434 : first = EntryLookup(key);
255 25434 : if (first == NULL) {
256 74 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
257 : key->id_name);
258 74 : return;
259 : }
260 : } else {
261 153145 : first = EntryLocate(key, &lchanged);
262 : }
263 :
264 178505 : if (data->id_name.empty()) {
265 : // property
266 55280 : first->set_last_change_at_to_now();
267 55280 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
268 48929 : IFMapIdentifier *identifier = LocateIdentifier(first, data->origin,
269 : key->id_seq_num);
270 48929 : identifier->SetProperty(data->metadata, data->content.get());
271 48929 : partition->Change(first);
272 : } else {
273 : IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(
274 6351 : first->Find(data->origin));
275 6351 : if (identifier == NULL) {
276 8 : return;
277 : }
278 6343 : identifier->ClearProperty(data->metadata);
279 : // Figure out whether to delete the identifier.
280 6343 : if (identifier->empty()) {
281 5255 : first->Remove(identifier);
282 : }
283 6343 : if (DeleteIfEmpty(first) == false) {
284 5878 : partition->Change(first);
285 : }
286 : }
287 55272 : return;
288 : }
289 :
290 123225 : IFMapNode *second = NULL;
291 123225 : bool rchanged = false;
292 123225 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
293 19009 : second = TableEntryLookup(rtable, data->id_name);
294 19009 : if (second == NULL) {
295 14 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
296 : data->id_name);
297 14 : return;
298 : }
299 : } else {
300 104216 : second = TableEntryLocate(rtable, data->id_name, &rchanged);
301 : }
302 :
303 123211 : IFMapNode *midnode = NULL;
304 123211 : bool mchanged = false;
305 :
306 123211 : if (mtable != NULL) {
307 : // link with attribute
308 79862 : string id_mid = LinkAttrKey(first, second);
309 79862 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
310 14348 : midnode = TableEntryLookup(mtable, id_mid);
311 14348 : if (midnode == NULL) {
312 23 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
313 : id_mid);
314 23 : return;
315 : }
316 : } else {
317 65514 : midnode = TableEntryLocate(mtable, id_mid, &mchanged);
318 : }
319 79839 : midnode->set_last_change_at_to_now();
320 79839 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
321 : IFMapLink *glink =
322 131028 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
323 65514 : data->metadata));
324 65514 : if (glink == NULL) {
325 125476 : glink = LinkNodeAdd(first, midnode, data->metadata,
326 62738 : key->id_seq_num, data->origin);
327 62738 : graph()->Link(first, midnode, glink);
328 : } else {
329 2776 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
330 : }
331 131028 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
332 65514 : data->metadata));
333 65514 : if (glink == NULL) {
334 125472 : glink = LinkNodeAdd(midnode, second, data->metadata,
335 62736 : key->id_seq_num, data->origin);
336 62736 : graph()->Link(midnode, second, glink);
337 : } else {
338 2778 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
339 : }
340 65514 : IFMapLinkAttr *link_attr = mtable->LocateLinkAttr(midnode,
341 : data->origin,
342 : key->id_seq_num);
343 65514 : mchanged |= link_attr->SetData(data->content.get());
344 : } else {
345 14325 : IFMapObject *object = midnode->Find(data->origin);
346 14325 : if (object == NULL) {
347 0 : return;
348 : }
349 14325 : midnode->Remove(object);
350 14325 : if (midnode->GetObject() != NULL) {
351 0 : return;
352 : }
353 14325 : IFMapOrigin origin(data->origin);
354 : IFMapLink *glink =
355 28650 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
356 14325 : data->metadata));
357 14325 : if (glink) LinkNodeDelete(glink, origin);
358 28650 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
359 14325 : data->metadata));
360 14325 : if (glink) LinkNodeDelete(glink, origin);
361 14325 : DeleteIfEmpty(first);
362 14325 : rtable->DeleteIfEmpty(second);
363 14325 : mtable->DeleteIfEmpty(midnode);
364 : }
365 79862 : } else {
366 : // link
367 43349 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
368 : // Link is added if not present
369 : IFMapLink *glink =
370 77404 : static_cast<IFMapLink *>(FindLinkNode(first, second,
371 38702 : data->metadata));
372 38702 : if (glink == NULL) {
373 68608 : glink = LinkNodeAdd(first, second, data->metadata,
374 34304 : key->id_seq_num, data->origin);
375 34304 : 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 4647 : IFMapLink *glink = FindLinkNode(first, second, data->metadata);
382 4647 : if (glink != NULL) {
383 4644 : IFMapOrigin origin(data->origin);
384 4644 : LinkNodeDelete(glink, origin);
385 : // check whether any of the identifiers can be deleted.
386 4644 : DeleteIfEmpty(first);
387 4644 : rtable->DeleteIfEmpty(second);
388 : }
389 : }
390 : }
391 :
392 123188 : if (lchanged) {
393 48440 : partition->Change(first);
394 : }
395 123188 : if (rchanged) {
396 55618 : rtable->Notify(second);
397 : }
398 123188 : if (mchanged) {
399 65126 : mtable->Notify(midnode);
400 : }
401 : }
402 :
403 1221917 : void IFMapServerTable::Clear() {
404 : DBTablePartition *partition = static_cast<DBTablePartition *>(
405 1221917 : GetTablePartition(0));
406 1221917 : assert(!HasListeners());
407 1221917 : for (IFMapNode *node = static_cast<IFMapNode *>(partition->GetFirst()),
408 1221917 : *next = NULL;
409 1369226 : node != NULL; node = next) {
410 147309 : next = static_cast<IFMapNode *>(partition->GetNext(node));
411 147309 : if (node->IsDeleted()) {
412 0 : continue;
413 : }
414 147309 : graph()->RemoveNode(node);
415 147309 : partition->Delete(node);
416 : }
417 1221917 : }
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 :
|