OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ifmap_server_table.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
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 
24 }
25 
27  const string &type, const string &name)
28  : origin(orig), id_type(type), id_name(name) {
29 }
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.
37 #if defined(__GNUC__)
38 #if (__GNUC_PREREQ(4, 2) > 0)
40  assert(has_destructor);
41 #endif
42 #endif
43  boost::checked_delete(content.release());
44 }
45 
46 
48  : IFMapTable(db, name, graph) {
49 }
50 
51 unique_ptr<DBEntry> IFMapServerTable::AllocEntry(const DBRequestKey *key) const {
52  unique_ptr<DBEntry> entry(
53  new IFMapNode(const_cast<IFMapServerTable *>(this)));
54  entry->SetKey(key);
55  return entry;
56 }
57 
58 static IFMapServerTable *TableFind(DB *db, const string &metadata) {
59  string name = metadata;
60  std::replace(name.begin(), name.end(), '-', '_');
61  name = "__ifmap__." + name + ".0";
62  IFMapServerTable *table =
63  static_cast<IFMapServerTable *>(db->FindTable(name));
64  return table;
65 }
66 
68  unique_ptr<DBEntry> key(AllocEntry(request));
69  IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
70  if ((node == NULL) || node->IsDeleted()) {
71  return NULL;
72  }
73  return node;
74 }
75 
77  unique_ptr<DBEntry> key(AllocEntry(request));
78  IFMapNode *node = static_cast<IFMapNode *>(Find(key.get()));
79  if (node != NULL) {
80  if (node->IsDeleted()) {
81  node->ClearDelete();
82  graph()->AddNode(node);
83  IFMAP_DEBUG(IFMapNodeOperation, "Re-creating", node->ToString());
84  *changep = true;
85  }
86  return node;
87  }
88  *changep = true;
89  node = const_cast<IFMapNode *>(
90  static_cast<const IFMapNode *>(key.release()));
91  DBTablePartition *partition =
92  static_cast<DBTablePartition *>(GetTablePartition(0));
93  partition->Add(node);
94  graph()->AddNode(node);
95  IFMAP_DEBUG(IFMapNodeOperation, "Creating", node->ToString());
96  return node;
97 }
98 
100  const string &id_name) {
101  RequestKey request;
102  request.id_name = id_name;
103  return table->EntryLookup(&request);
104 }
105 
107  const string &id_name,
108  bool *changep) {
109  RequestKey request;
110  request.id_name = id_name;
111  return table->EntryLocate(&request, changep);
112 }
113 
115  const string &metadata) {
116  IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
117  database()->FindTable("__ifmap_metadata__.0"));
118  assert(table != NULL);
119  IFMapLink *link = table->FindLink(metadata, first, second);
120  return (link ? (link->IsDeleted() ? NULL : link) : NULL);
121 }
122 
124  const string &metadata,
125  uint64_t sequence_number,
126  const IFMapOrigin &origin) {
127  IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
128  database()->FindTable("__ifmap_metadata__.0"));
129  assert(table != NULL);
130  IFMAP_DEBUG(IFMapLinkOperation, "Creating", metadata);
131  return table->AddLink(first, second, metadata, sequence_number, origin);
132 }
133 
134 void IFMapServerTable::LinkNodeUpdate(IFMapLink *link, uint64_t sequence_number,
135  const IFMapOrigin &origin) {
137  link->UpdateProperties(origin, sequence_number);
138 }
139 
141  const IFMapOrigin &origin) {
142  IFMapLinkTable *table = static_cast<IFMapLinkTable *>(
143  database()->FindTable("__ifmap_metadata__.0"));
144  assert(table != NULL);
145  IFMAP_DEBUG(IFMapLinkOperation, "Deleting", link->ToString());
146  table->DeleteLink(link, origin);
147 }
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 std::string IFMapServerTable::LinkAttrKey(IFMapNode *first, IFMapNode *second) {
152  ostringstream oss;
153  oss << "attr(";
154  if (first->IsLess(*second)) {
155  oss << first->name() << "," << second->name();
156  } else {
157  oss << second->name() << "," << first->name();
158  }
159  oss << ")";
160  return oss.str();
161 }
162 
164  IFMAP_DEBUG(IFMapNodeOperation, "Deleting", node->ToString());
165  DBTablePartition *partition =
166  static_cast<DBTablePartition *>(GetTablePartition(0));
167  graph()->RemoveNode(node);
168  partition->Delete(node);
169 }
170 
172  DBTablePartition *partition =
173  static_cast<DBTablePartition *>(GetTablePartition(0));
174  partition->Change(node);
175 }
176 
178  if ((node->GetObject() == NULL) && !node->HasAdjacencies(graph())) {
179  DeleteNode(node);
180  return true;
181  }
182  return false;
183 }
184 
186  IFMapOrigin origin) {
187  IFMapObject *object = node->Find(origin);
188  if (object == NULL) {
189  object = AllocObject();
190  object->set_origin(origin);
191  node->Insert(object);
192  }
193  return object;
194 }
195 
197  IFMapOrigin origin,
198  uint64_t sequence_number) {
199  IFMapObject *object = LocateObject(node, origin);
200  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  if (object->sequence_number() != sequence_number) {
206  IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(object);
207  identifier->TransferPropertyToOldProperty();
208  object->set_sequence_number(sequence_number);
209  }
210  return static_cast<IFMapIdentifier *>(object);
211 }
212 
214  IFMapOrigin origin,
215  uint64_t sequence_number) {
216  IFMapObject *object = LocateObject(node, origin);
217  assert(object);
218  object->set_sequence_number(sequence_number);
219 
220  return static_cast<IFMapLinkAttr *>(object);
221 }
222 
224  DBRequest *request) {
225  assert(request->oper == DBRequest::DB_ENTRY_ADD_CHANGE ||
226  request->oper == DBRequest::DB_ENTRY_DELETE);
227  RequestKey *key = static_cast<RequestKey *>(request->key.get());
228  RequestData *data = static_cast<RequestData *>(request->data.get());
229  assert(data != NULL);
230 
231  IFMapServerTable *rtable = NULL;
232  IFMapServerTable *mtable = NULL;
233 
234  // Sanity checks before allocation resources.
235  if (!data->id_name.empty()) {
236  rtable = TableFind(database(), data->id_type);
237  if (!rtable) {
238  IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
239  data->id_type);
240  return;
241  }
242  mtable = TableFind(database(), data->metadata);
243  if (mtable == NULL && request->oper == DBRequest::DB_ENTRY_ADD_CHANGE &&
244  data->content.get() != NULL) {
245  IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table",
246  data->metadata);
247  return;
248  }
249  }
250 
251  IFMapNode *first = NULL;
252  bool lchanged = false;
253  if (request->oper == DBRequest::DB_ENTRY_DELETE) {
254  first = EntryLookup(key);
255  if (first == NULL) {
256  IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
257  key->id_name);
258  return;
259  }
260  } else {
261  first = EntryLocate(key, &lchanged);
262  }
263 
264  if (data->id_name.empty()) {
265  // property
266  first->set_last_change_at_to_now();
267  if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
268  IFMapIdentifier *identifier = LocateIdentifier(first, data->origin,
269  key->id_seq_num);
270  identifier->SetProperty(data->metadata, data->content.get());
271  partition->Change(first);
272  } else {
273  IFMapIdentifier *identifier = static_cast<IFMapIdentifier *>(
274  first->Find(data->origin));
275  if (identifier == NULL) {
276  return;
277  }
278  identifier->ClearProperty(data->metadata);
279  // Figure out whether to delete the identifier.
280  if (identifier->empty()) {
281  first->Remove(identifier);
282  }
283  if (DeleteIfEmpty(first) == false) {
284  partition->Change(first);
285  }
286  }
287  return;
288  }
289 
290  IFMapNode *second = NULL;
291  bool rchanged = false;
292  if (request->oper == DBRequest::DB_ENTRY_DELETE) {
293  second = TableEntryLookup(rtable, data->id_name);
294  if (second == NULL) {
295  IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
296  data->id_name);
297  return;
298  }
299  } else {
300  second = TableEntryLocate(rtable, data->id_name, &rchanged);
301  }
302 
303  IFMapNode *midnode = NULL;
304  bool mchanged = false;
305 
306  if (mtable != NULL) {
307  // link with attribute
308  string id_mid = LinkAttrKey(first, second);
309  if (request->oper == DBRequest::DB_ENTRY_DELETE) {
310  midnode = TableEntryLookup(mtable, id_mid);
311  if (midnode == NULL) {
312  IFMAP_WARN(IFMapIdentifierNotFound, "Cant find identifier",
313  id_mid);
314  return;
315  }
316  } else {
317  midnode = TableEntryLocate(mtable, id_mid, &mchanged);
318  }
319  midnode->set_last_change_at_to_now();
320  if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
321  IFMapLink *glink =
322  static_cast<IFMapLink *>(FindLinkNode(first, midnode,
323  data->metadata));
324  if (glink == NULL) {
325  glink = LinkNodeAdd(first, midnode, data->metadata,
326  key->id_seq_num, data->origin);
327  graph()->Link(first, midnode, glink);
328  } else {
329  LinkNodeUpdate(glink, key->id_seq_num, data->origin);
330  }
331  glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
332  data->metadata));
333  if (glink == NULL) {
334  glink = LinkNodeAdd(midnode, second, data->metadata,
335  key->id_seq_num, data->origin);
336  graph()->Link(midnode, second, glink);
337  } else {
338  LinkNodeUpdate(glink, key->id_seq_num, data->origin);
339  }
340  IFMapLinkAttr *link_attr = mtable->LocateLinkAttr(midnode,
341  data->origin,
342  key->id_seq_num);
343  mchanged |= link_attr->SetData(data->content.get());
344  } else {
345  IFMapObject *object = midnode->Find(data->origin);
346  if (object == NULL) {
347  return;
348  }
349  midnode->Remove(object);
350  if (midnode->GetObject() != NULL) {
351  return;
352  }
353  IFMapOrigin origin(data->origin);
354  IFMapLink *glink =
355  static_cast<IFMapLink *>(FindLinkNode(first, midnode,
356  data->metadata));
357  if (glink) LinkNodeDelete(glink, origin);
358  glink = static_cast<IFMapLink *>(FindLinkNode(midnode, second,
359  data->metadata));
360  if (glink) LinkNodeDelete(glink, origin);
361  DeleteIfEmpty(first);
362  rtable->DeleteIfEmpty(second);
363  mtable->DeleteIfEmpty(midnode);
364  }
365  } else {
366  // link
367  if (request->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
368  // Link is added if not present
369  IFMapLink *glink =
370  static_cast<IFMapLink *>(FindLinkNode(first, second,
371  data->metadata));
372  if (glink == NULL) {
373  glink = LinkNodeAdd(first, second, data->metadata,
374  key->id_seq_num, data->origin);
375  graph()->Link(first, second, glink);
376  } else {
377  LinkNodeUpdate(glink, key->id_seq_num, data->origin);
378  }
379  } else {
380  // TODO: check if the edge is present and ignore otherwise.
381  IFMapLink *glink = FindLinkNode(first, second, data->metadata);
382  if (glink != NULL) {
383  IFMapOrigin origin(data->origin);
384  LinkNodeDelete(glink, origin);
385  // check whether any of the identifiers can be deleted.
386  DeleteIfEmpty(first);
387  rtable->DeleteIfEmpty(second);
388  }
389  }
390  }
391 
392  if (lchanged) {
393  partition->Change(first);
394  }
395  if (rchanged) {
396  rtable->Notify(second);
397  }
398  if (mchanged) {
399  mtable->Notify(midnode);
400  }
401 }
402 
404  DBTablePartition *partition = static_cast<DBTablePartition *>(
405  GetTablePartition(0));
406  assert(!HasListeners());
407  for (IFMapNode *node = static_cast<IFMapNode *>(partition->GetFirst()),
408  *next = NULL;
409  node != NULL; node = next) {
410  next = static_cast<IFMapNode *>(partition->GetNext(node));
411  if (node->IsDeleted()) {
412  continue;
413  }
414  graph()->RemoveNode(node);
415  partition->Delete(node);
416  }
417 }
418 
419 // This is called in the context of the virtual_router table i.e. 'this' points
420 // to __ifmap__.virtual_router.0
421 void IFMapServerTable::IFMapVmSubscribe(const std::string &vr_name,
422  const std::string &vm_name,
423  bool subscribe, bool has_vms) {
424  if (subscribe) {
425  IFMapProcVmSubscribe(vr_name, vm_name);
426  } else {
427  IFMapProcVmUnsubscribe(vr_name, vm_name, has_vms);
428  }
429 }
430 
432  IFMapNode *vm_node) {
433  // Add the link if it does not exist. If it does, add XMPP as origin
434  uint64_t sequence_number = 0;
436 
437  std::string metadata = std::string("virtual-router-virtual-machine");
438  IFMapLink *glink =
439  static_cast<IFMapLink *>(FindLinkNode(vr_node, vm_node, metadata));
440  if (glink == NULL) {
441  glink = LinkNodeAdd(vr_node, vm_node, metadata, sequence_number, origin);
442  graph()->Link(vr_node, vm_node, glink);
443  } else {
444  glink->AddOriginInfo(origin, sequence_number);
445  }
446 }
447 
448 // Process the vm-subscribe only after a config-add of the vm
449 void IFMapServerTable::IFMapProcVmSubscribe(const std::string &vr_name,
450  const std::string &vm_name) {
451  bool changed = false;
452 
453  // Lookup the node corresponding to vr_name
454  RequestKey request;
455  request.id_name = vr_name;
456  IFMapNode *vr_node = EntryLookup(&request);
457  if (vr_node == NULL) {
458  vr_node = EntryLocate(&request, &changed);
459  }
461 
462  // Lookup the node corresponding to vm_name
463  IFMapServerTable *vm_table = static_cast<IFMapServerTable *>(
464  database()->FindTable("__ifmap__.virtual_machine.0"));
465  assert(vm_table != NULL);
466  request.id_name = vm_name;
467  IFMapNode *vm_node = vm_table->EntryLookup(&request);
468  assert(vm_node != NULL);
469  vm_table->LocateIdentifier(vm_node, IFMapOrigin(IFMapOrigin::XMPP), 0);
470 
471  IFMapAddVrVmLink(vr_node, vm_node);
472 }
473 
475  IFMapNode *vm_node) {
476  // Remove XMPP as origin. If there are no more origin's, delete the link.
478  std::string metadata = std::string("virtual-router-virtual-machine");
479  IFMapLink *glink =
480  static_cast<IFMapLink *>(FindLinkNode(vr_node, vm_node, metadata));
481  LinkNodeDelete(glink, origin);
482 }
483 
484 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  RequestKey request;
489  request.id_name = vr_name;
490  IFMapNode *vr_node = EntryLookup(&request);
491  assert(vr_node != NULL);
492 
493  // Lookup the node corresponding to vm_name
494  IFMapServerTable *vm_table = static_cast<IFMapServerTable *>(
495  database()->FindTable("__ifmap__.virtual_machine.0"));
496  assert(vm_table != NULL);
497  request.id_name = vm_name;
498  IFMapNode *vm_node = vm_table->EntryLookup(&request);
499  assert(vm_node != NULL);
500 
501  IFMapRemoveVrVmLink(vr_node, vm_node);
502 
504  RemoveObjectAndDeleteNode(vm_node, origin);
505 
506  // Remove XMPP as origin from the VR only if all the VMs are gone
507  if (!has_vms) {
508  RemoveObjectAndDeleteNode(vr_node, origin);
509  }
510 }
511 
513  const IFMapOrigin &origin) {
514  IFMapServerTable *table = static_cast<IFMapServerTable *>(node->table());
515  assert(table);
516  IFMapObject *object = node->Find(origin);
517  if (object) {
518  node->Remove(object);
519  }
520  table->DeleteIfEmpty(node);
521 }
522 
IFMapLink * FindLinkNode(IFMapNode *first, IFMapNode *second, const std::string &metadata)
void Notify(IFMapNode *node)
const DBGraph * graph() const
virtual void Clear()
static void RemoveObjectAndDeleteNode(IFMapNode *node, const IFMapOrigin &origin)
static IFMapServerTable * TableFind(DB *db, const string &metadata)
IFMapLinkAttr * LocateLinkAttr(IFMapNode *node, IFMapOrigin origin, uint64_t sequence_number)
IFMapObject * LocateObject(IFMapNode *node, IFMapOrigin origin)
virtual IFMapObject * AllocObject()=0
virtual std::string ToString() const
Definition: ifmap_node.cc:31
void set_last_change_at_to_now()
Definition: db_entry.cc:96
void Remove(IFMapObject *obj)
Definition: ifmap_node.cc:58
bool IsDeleted() const
Definition: db_entry.h:49
virtual bool empty() const
Definition: ifmap_object.h:93
virtual DBEntry * GetNext(const DBEntryBase *entry)
IFMapNode * EntryLocate(RequestKey *key, bool *changep)
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
IFMapTable * table()
Definition: ifmap_node.h:29
DB * database()
Definition: db_table.h:107
std::unique_ptr< AutogenProperty > content
void DeleteLink(IFMapLink *link, const IFMapOrigin &origin)
void Delete(DBEntryBase *)
bool HasAdjacencies(DBGraph *graph) const
IFMapLink * FindLink(const std::string &metadata, IFMapNode *left, IFMapNode *right)
static IFMapNode * TableEntryLookup(IFMapServerTable *table, const std::string &id_name)
virtual void Change(DBEntry *entry)
#define IFMAP_DEBUG(obj,...)
Definition: ifmap_log.h:33
IFMapLink * AddLink(IFMapNode *left, IFMapNode *right, const std::string &metadata, uint64_t sequence_number, const IFMapOrigin &origin)
Definition: db.h:24
void IFMapProcVmSubscribe(const std::string &vr_name, const std::string &vm_name)
IFMapServerTable(DB *db, const std::string &name, DBGraph *graph)
IFMapLink * LinkNodeAdd(IFMapNode *first, IFMapNode *second, const std::string &metadata, uint64_t sequence_number, const IFMapOrigin &origin)
void IFMapVmSubscribe(const std::string &vr_name, const std::string &vm_name, bool subscribe, bool has_vms)
void AddNode(DBGraphVertex *entry)
Definition: db_graph.cc:30
uint64_t sequence_number()
Definition: ifmap_object.h:33
uint8_t type
Definition: load_balance.h:109
IFMapIdentifier * LocateIdentifier(IFMapNode *node, IFMapOrigin origin, uint64_t sequence_number)
void IFMapRemoveVrVmLink(IFMapNode *vr_node, IFMapNode *vm_node)
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
void Insert(IFMapObject *obj)
Definition: ifmap_node.cc:49
DBOperation oper
Definition: db_table.h:42
void RemoveNode(DBGraphVertex *entry)
Definition: db_graph.cc:36
IFMapObject * Find(IFMapOrigin origin)
Definition: ifmap_node.cc:38
virtual bool SetData(const AutogenProperty *data)=0
const std::string & name() const
Definition: db_table.h:110
void ClearDelete()
Definition: db_entry.h:48
const std::string & name() const
Definition: ifmap_node.h:48
Edge Link(DBGraphVertex *lhs, DBGraphVertex *rhs, DBGraphEdge *link)
Definition: db_graph.cc:41
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:436
IFMapObject * GetObject()
Definition: ifmap_node.cc:63
void IFMapProcVmUnsubscribe(const std::string &vr_name, const std::string &vm_name, bool has_vms)
#define IFMAP_WARN(obj,...)
Definition: ifmap_log.h:72
void DeleteNode(IFMapNode *node)
static IFMapNode * TableEntryLocate(IFMapServerTable *table, const std::string &id_name, bool *changep)
virtual bool IsLess(const DBEntry &db_entry) const
Definition: ifmap_node.h:36
bool HasListeners() const
Definition: db_table.cc:234
DBEntry * Find(const DBEntry *entry)
Definition: db_table.cc:469
virtual bool SetProperty(const std::string &attr_key, AutogenProperty *data)=0
void IFMapAddVrVmLink(IFMapNode *vr_node, IFMapNode *vm_node)
virtual std::unique_ptr< DBEntry > AllocEntry(const DBRequestKey *key) const
virtual DBEntry * GetFirst()
virtual void Add(DBEntry *entry)
#define IFMAP_TRACE(obj,...)
Definition: ifmap_log.h:26
IFMapNode * EntryLookup(RequestKey *key)
void TransferPropertyToOldProperty()
Definition: ifmap_object.cc:27
void LinkNodeDelete(IFMapLink *link, const IFMapOrigin &origin)
virtual void Input(DBTablePartition *partition, DBClient *client, DBRequest *req)
static std::string LinkAttrKey(IFMapNode *first, IFMapNode *second)
bool DeleteIfEmpty(IFMapNode *node)
void LinkNodeUpdate(IFMapLink *link, uint64_t sequence_number, const IFMapOrigin &origin)
DBTableBase * FindTable(const std::string &name)
Definition: db.cc:68
virtual void ClearProperty(const std::string &attr_key)=0