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 4283 : IFMapServerTable::RequestData::RequestData() {
24 4283 : }
25 :
26 6170 : IFMapServerTable::RequestData::RequestData(IFMapOrigin::Origin orig,
27 6170 : const string &type, const string &name)
28 6170 : : origin(orig), id_type(type), id_name(name) {
29 6170 : }
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 20906 : IFMapServerTable::RequestData::~RequestData() {
37 : #if defined(__GNUC__)
38 : #if (__GNUC_PREREQ(4, 2) > 0)
39 : boost::has_virtual_destructor<AutogenProperty>::type has_destructor;
40 10453 : assert(has_destructor);
41 : #endif
42 : #endif
43 10453 : boost::checked_delete(content.release());
44 20906 : }
45 :
46 :
47 90896 : IFMapServerTable::IFMapServerTable(DB *db, const string &name, DBGraph *graph)
48 90896 : : IFMapTable(db, name, graph) {
49 90896 : }
50 :
51 23227 : unique_ptr<DBEntry> IFMapServerTable::AllocEntry(const DBRequestKey *key) const {
52 : unique_ptr<DBEntry> entry(
53 23227 : new IFMapNode(const_cast<IFMapServerTable *>(this)));
54 23227 : entry->SetKey(key);
55 23227 : return entry;
56 0 : }
57 :
58 9904 : static IFMapServerTable *TableFind(DB *db, const string &metadata) {
59 9904 : string name = metadata;
60 9904 : std::replace(name.begin(), name.end(), '-', '_');
61 9904 : name = "__ifmap__." + name + ".0";
62 : IFMapServerTable *table =
63 9904 : static_cast<IFMapServerTable *>(db->FindTable(name));
64 9904 : return table;
65 9904 : }
66 :
67 633 : IFMapNode *IFMapServerTable::EntryLookup(RequestKey *request) {
68 633 : unique_ptr<DBEntry> key(AllocEntry(request));
69 633 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
70 633 : if ((node == NULL) || node->IsDeleted()) {
71 4 : return NULL;
72 : }
73 629 : return node;
74 633 : }
75 :
76 16540 : IFMapNode *IFMapServerTable::EntryLocate(RequestKey *request, bool *changep) {
77 16540 : unique_ptr<DBEntry> key(AllocEntry(request));
78 16540 : IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
79 16540 : if (node != NULL) {
80 11145 : 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 11145 : return node;
87 : }
88 5395 : *changep = true;
89 : node = const_cast<IFMapNode *>(
90 5395 : static_cast<const IFMapNode *>(key.release()));
91 : DBTablePartition *partition =
92 5395 : static_cast<DBTablePartition *>(GetTablePartition(0));
93 5395 : partition->Add(node);
94 5395 : graph()->AddNode(node);
95 5395 : IFMAP_DEBUG(IFMapNodeOperation, "Creating", node->ToString());
96 5395 : return node;
97 16540 : }
98 :
99 170 : IFMapNode *IFMapServerTable::TableEntryLookup(IFMapServerTable *table,
100 : const string &id_name) {
101 170 : RequestKey request;
102 170 : request.id_name = id_name;
103 340 : return table->EntryLookup(&request);
104 170 : }
105 :
106 6454 : IFMapNode *IFMapServerTable::TableEntryLocate(IFMapServerTable *table,
107 : const string &id_name,
108 : bool *changep) {
109 6454 : RequestKey request;
110 6454 : request.id_name = id_name;
111 12908 : return table->EntryLocate(&request, changep);
112 6454 : }
113 :
114 6682 : IFMapLink *IFMapServerTable::FindLinkNode(IFMapNode *first, IFMapNode *second,
115 : const string &metadata) {
116 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
117 6682 : database()->FindTable("__ifmap_metadata__.0"));
118 6682 : assert(table != NULL);
119 6682 : IFMapLink *link = table->FindLink(metadata, first, second);
120 6682 : return (link ? (link->IsDeleted() ? NULL : link) : NULL);
121 : }
122 :
123 5664 : 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 5664 : database()->FindTable("__ifmap_metadata__.0"));
129 5664 : assert(table != NULL);
130 5664 : IFMAP_DEBUG(IFMapLinkOperation, "Creating", metadata);
131 5664 : return table->AddLink(first, second, metadata, sequence_number, origin);
132 : }
133 :
134 838 : void IFMapServerTable::LinkNodeUpdate(IFMapLink *link, uint64_t sequence_number,
135 : const IFMapOrigin &origin) {
136 838 : link->set_last_change_at_to_now();
137 838 : link->UpdateProperties(origin, sequence_number);
138 838 : }
139 :
140 176 : void IFMapServerTable::LinkNodeDelete(IFMapLink *link,
141 : const IFMapOrigin &origin) {
142 : IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
143 176 : database()->FindTable("__ifmap_metadata__.0"));
144 176 : assert(table != NULL);
145 176 : IFMAP_DEBUG(IFMapLinkOperation, "Deleting", link->ToString());
146 176 : table->DeleteLink(link, origin);
147 176 : }
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 1675 : std::string IFMapServerTable::LinkAttrKey(IFMapNode *first, IFMapNode *second) {
152 1675 : ostringstream oss;
153 1675 : oss << "attr(";
154 1675 : if (first->IsLess(*second)) {
155 1527 : oss << first->name() << "," << second->name();
156 : } else {
157 148 : oss << second->name() << "," << first->name();
158 : }
159 1675 : oss << ")";
160 3350 : return oss.str();
161 1675 : }
162 :
163 242 : void IFMapServerTable::DeleteNode(IFMapNode *node) {
164 242 : IFMAP_DEBUG(IFMapNodeOperation, "Deleting", node->ToString());
165 : DBTablePartition *partition =
166 242 : static_cast<DBTablePartition *>(GetTablePartition(0));
167 242 : graph()->RemoveNode(node);
168 242 : partition->Delete(node);
169 242 : }
170 :
171 3098 : void IFMapServerTable::Notify(IFMapNode *node) {
172 : DBTablePartition *partition =
173 3098 : static_cast<DBTablePartition *>(GetTablePartition(0));
174 3098 : partition->Change(node);
175 3098 : }
176 :
177 537 : bool IFMapServerTable::DeleteIfEmpty(IFMapNode *node) {
178 537 : if ((node->GetObject() == NULL) && !node->HasAdjacencies(graph())) {
179 242 : DeleteNode(node);
180 242 : return true;
181 : }
182 295 : return false;
183 : }
184 :
185 7040 : IFMapObject *IFMapServerTable::LocateObject(IFMapNode *node,
186 : IFMapOrigin origin) {
187 7040 : IFMapObject *object = node->Find(origin);
188 7040 : if (object == NULL) {
189 4700 : object = AllocObject();
190 4700 : object->set_origin(origin);
191 4700 : node->Insert(object);
192 : }
193 7040 : return object;
194 : }
195 :
196 5388 : IFMapIdentifier *IFMapServerTable::LocateIdentifier(IFMapNode *node,
197 : IFMapOrigin origin,
198 : uint64_t sequence_number) {
199 5388 : IFMapObject *object = LocateObject(node, origin);
200 5388 : 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 5388 : 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 5388 : return static_cast<IFMapIdentifier *>(object);
211 : }
212 :
213 1652 : IFMapLinkAttr *IFMapServerTable::LocateLinkAttr(IFMapNode *node,
214 : IFMapOrigin origin,
215 : uint64_t sequence_number) {
216 1652 : IFMapObject *object = LocateObject(node, origin);
217 1652 : assert(object);
218 1652 : object->set_sequence_number(sequence_number);
219 :
220 1652 : return static_cast<IFMapLinkAttr *>(object);
221 : }
222 :
223 10445 : void IFMapServerTable::Input(DBTablePartition *partition, DBClient *client,
224 : DBRequest *request) {
225 10445 : assert(request->oper == DBRequest::DB_ENTRY_ADD_CHANGE ||
226 : request->oper == DBRequest::DB_ENTRY_DELETE);
227 10445 : RequestKey *key = static_cast<RequestKey *>(request->key.get());
228 10445 : RequestData *data = static_cast<RequestData *>(request->data.get());
229 10445 : assert(data != NULL);
230 :
231 10445 : IFMapServerTable *rtable = NULL;
232 10445 : IFMapServerTable *mtable = NULL;
233 :
234 : // Sanity checks before allocation resources.
235 10445 : if (!data->id_name.empty()) {
236 4952 : rtable = TableFind(database(), data->id_type);
237 4952 : if (!rtable) {
238 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
239 : data->id_type);
240 5495 : return;
241 : }
242 4952 : mtable = TableFind(database(), data->metadata);
243 8102 : if (mtable == NULL && request->oper == DBRequest::DB_ENTRY_ADD_CHANGE &&
244 3150 : data->content.get() != NULL) {
245 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
246 : data->metadata);
247 0 : return;
248 : }
249 : }
250 :
251 10445 : IFMapNode *first = NULL;
252 10445 : bool lchanged = false;
253 10445 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
254 359 : first = EntryLookup(key);
255 359 : if (first == NULL) {
256 4 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
257 : key->id_name);
258 4 : return;
259 : }
260 : } else {
261 10086 : first = EntryLocate(key, &lchanged);
262 : }
263 :
264 10441 : if (data->id_name.empty()) {
265 : // property
266 5491 : first->set_last_change_at_to_now();
267 5491 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
268 5284 : IFMapIdentifier *identifier = LocateIdentifier(first, data->origin,
269 : key->id_seq_num);
270 5284 : identifier->SetProperty(data->metadata, data->content.get());
271 5284 : partition->Change(first);
272 : } else {
273 : IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(
274 207 : first->Find(data->origin));
275 207 : if (identifier == NULL) {
276 0 : return;
277 : }
278 207 : identifier->ClearProperty(data->metadata);
279 : // Figure out whether to delete the identifier.
280 207 : if (identifier->empty()) {
281 167 : first->Remove(identifier);
282 : }
283 207 : if (DeleteIfEmpty(first) == false) {
284 140 : partition->Change(first);
285 : }
286 : }
287 5491 : return;
288 : }
289 :
290 4950 : IFMapNode *second = NULL;
291 4950 : bool rchanged = false;
292 4950 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
293 148 : second = TableEntryLookup(rtable, data->id_name);
294 148 : if (second == NULL) {
295 0 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
296 : data->id_name);
297 0 : return;
298 : }
299 : } else {
300 4802 : second = TableEntryLocate(rtable, data->id_name, &rchanged);
301 : }
302 :
303 4950 : IFMapNode *midnode = NULL;
304 4950 : bool mchanged = false;
305 :
306 4950 : if (mtable != NULL) {
307 : // link with attribute
308 1674 : string id_mid = LinkAttrKey(first, second);
309 1674 : if (request->oper == DBRequest::DB_ENTRY_DELETE) {
310 22 : midnode = TableEntryLookup(mtable, id_mid);
311 22 : if (midnode == NULL) {
312 0 : IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
313 : id_mid);
314 0 : return;
315 : }
316 : } else {
317 1652 : midnode = TableEntryLocate(mtable, id_mid, &mchanged);
318 : }
319 1674 : midnode->set_last_change_at_to_now();
320 1674 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
321 : IFMapLink *glink =
322 3304 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
323 1652 : data->metadata));
324 1652 : if (glink == NULL) {
325 2900 : glink = LinkNodeAdd(first, midnode, data->metadata,
326 1450 : key->id_seq_num, data->origin);
327 1450 : graph()->Link(first, midnode, glink);
328 : } else {
329 202 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
330 : }
331 3304 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
332 1652 : data->metadata));
333 1652 : if (glink == NULL) {
334 2896 : glink = LinkNodeAdd(midnode, second, data->metadata,
335 1448 : key->id_seq_num, data->origin);
336 1448 : graph()->Link(midnode, second, glink);
337 : } else {
338 204 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
339 : }
340 1652 : IFMapLinkAttr *link_attr = mtable->LocateLinkAttr(midnode,
341 : data->origin,
342 : key->id_seq_num);
343 1652 : mchanged |= link_attr->SetData(data->content.get());
344 : } else {
345 22 : IFMapObject *object = midnode->Find(data->origin);
346 22 : if (object == NULL) {
347 0 : return;
348 : }
349 22 : midnode->Remove(object);
350 22 : if (midnode->GetObject() != NULL) {
351 0 : return;
352 : }
353 22 : IFMapOrigin origin(data->origin);
354 : IFMapLink *glink =
355 44 : static_cast<IFMapLink *>(FindLinkNode(first, midnode,
356 22 : data->metadata));
357 22 : if (glink) LinkNodeDelete(glink, origin);
358 44 : glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
359 22 : data->metadata));
360 22 : if (glink) LinkNodeDelete(glink, origin);
361 22 : DeleteIfEmpty(first);
362 22 : rtable->DeleteIfEmpty(second);
363 22 : mtable->DeleteIfEmpty(midnode);
364 : }
365 1674 : } else {
366 : // link
367 3276 : if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
368 : // Link is added if not present
369 : IFMapLink *glink =
370 6300 : static_cast<IFMapLink *>(FindLinkNode(first, second,
371 3150 : data->metadata));
372 3150 : if (glink == NULL) {
373 5436 : glink = LinkNodeAdd(first, second, data->metadata,
374 2718 : key->id_seq_num, data->origin);
375 2718 : graph()->Link(first, second, glink);
376 : } else {
377 432 : LinkNodeUpdate(glink, key->id_seq_num, data->origin);
378 : }
379 : } else {
380 : // TODO: check if the edge is present and ignore otherwise.
381 126 : IFMapLink *glink = FindLinkNode(first, second, data->metadata);
382 126 : if (glink != NULL) {
383 126 : IFMapOrigin origin(data->origin);
384 126 : LinkNodeDelete(glink, origin);
385 : // check whether any of the identifiers can be deleted.
386 126 : DeleteIfEmpty(first);
387 126 : rtable->DeleteIfEmpty(second);
388 : }
389 : }
390 : }
391 :
392 4950 : if (lchanged) {
393 544 : partition->Change(first);
394 : }
395 4950 : if (rchanged) {
396 1446 : rtable->Notify(second);
397 : }
398 4950 : if (mchanged) {
399 1652 : mtable->Notify(midnode);
400 : }
401 : }
402 :
403 88176 : void IFMapServerTable::Clear() {
404 : DBTablePartition *partition = static_cast<DBTablePartition *>(
405 88176 : GetTablePartition(0));
406 88176 : assert(!HasListeners());
407 88176 : for (IFMapNode *node = static_cast<IFMapNode *>(partition->GetFirst()),
408 88176 : *next = NULL;
409 93333 : node != NULL; node = next) {
410 5157 : next = static_cast<IFMapNode *>(partition->GetNext(node));
411 5157 : if (node->IsDeleted()) {
412 0 : continue;
413 : }
414 5157 : graph()->RemoveNode(node);
415 5157 : partition->Delete(node);
416 : }
417 88176 : }
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 :
|