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