OpenSDN source code
ifmap_graph_walker.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
6 
7 #include "base/logging.h"
8 #include "base/task_trigger.h"
9 #include "db/db_graph.h"
10 #include "db/db_table.h"
11 #include "ifmap/ifmap_client.h"
12 #include "ifmap/ifmap_exporter.h"
13 #include "ifmap/ifmap_link.h"
14 #include "ifmap/ifmap_log.h"
15 #include "ifmap/ifmap_table.h"
16 #include "ifmap/ifmap_server.h"
17 #include "ifmap/ifmap_log_types.h"
18 #include "ifmap/ifmap_update.h"
19 #include "ifmap/ifmap_util.h"
20 #include "schema/vnc_cfg_types.h"
21 
23 public:
25  const IFMapTypenameWhiteList *type_filter,
26  const BitSet &bitset)
27  : exporter_(exporter),
28  type_filter_(type_filter),
29  bset_(bitset) {
30  }
31 
32  bool VertexFilter(const DBGraphVertex *vertex) const {
33  return type_filter_->VertexFilter(vertex);
34  }
35 
36  bool EdgeFilter(const DBGraphVertex *source, const DBGraphVertex *target,
37  const DBGraphEdge *edge) const {
38  const IFMapNode *tgt = static_cast<const IFMapNode *>(target);
39  const IFMapNodeState *state = NodeStateLookup(tgt);
40  if (state != NULL && state->interest().Contains(bset_)) {
41  return false;
42  }
43 
44  return true;
45  }
46 
47  const IFMapNodeState *NodeStateLookup(const IFMapNode *node) const {
48  const DBTable *table = node->table();
49  const DBState *state =
50  node->GetState(table, exporter_->TableListenerId(table));
51  return static_cast<const IFMapNodeState *>(state);
52  }
53 
55  const DBGraphVertex *vertex) const {
56  return type_filter_->AllowedEdges(vertex);
57  }
58 private:
61  const BitSet &bset_;
62 };
63 
65  : graph_(graph),
66  exporter_(exporter),
67  link_delete_walk_trigger_(new TaskTrigger(
68  [this](){ return LinkDeleteWalk(); },
69  TaskScheduler::GetInstance()->GetTaskId("db::IFMapTable"), 0)),
70  walk_client_index_(BitSet::npos) {
71  traversal_white_list_.reset(new IFMapTypenameWhiteList());
72  AddNodesToWhitelist();
73 }
74 
76 }
77 
79  DBTable *table = exporter_->link_table();
80  table->Change(edge);
81 }
82 
84  IFMapNode *node = static_cast<IFMapNode *>(vertex);
86  IFMAP_DEBUG(JoinVertex, vertex->ToString(), state->interest().ToString(),
87  bset.ToString());
88  exporter_->StateInterestOr(state, bset);
89  node->table()->Change(node);
90 }
91 
93  const BitSet &bset) {
95  graph_->Visit(rnode,
96  [this, &bset](DBGraphVertex *v) { JoinVertex(v, bset); },
97  [this, &bset](DBGraphEdge *e) { NotifyEdge(e, bset); },
98  filter);
99 }
100 
101 void IFMapGraphWalker::LinkAdd(IFMapLink *link, IFMapNode *lnode, const BitSet &lhs,
102  IFMapNode *rnode, const BitSet &rhs) {
103  IFMAP_DEBUG(LinkOper, "LinkAdd", lnode->ToString(), rnode->ToString(),
104  lhs.ToString(), rhs.ToString());
105 
106  // Ensure that nodes are passed are indeed nodes and not links.
107  assert(dynamic_cast<IFMapNode *>(lnode));
108  assert(dynamic_cast<IFMapNode *>(rnode));
109 
110  assert(!dynamic_cast<IFMapLink *>(lnode));
111  assert(!dynamic_cast<IFMapLink *>(rnode));
112 
113  if (!lhs.empty() && !rhs.Contains(lhs) &&
114  traversal_white_list_->VertexFilter(rnode) &&
115  traversal_white_list_->EdgeFilter(lnode, rnode, link)) {
116  ProcessLinkAdd(lnode, rnode, lhs);
117  }
118  if (!rhs.empty() && !lhs.Contains(rhs) &&
119  traversal_white_list_->VertexFilter(lnode) &&
120  traversal_white_list_->EdgeFilter(rnode, lnode, link)) {
121  ProcessLinkAdd(rnode, lnode, rhs);
122  }
123 }
124 
126  OrLinkDeleteClients(bset); // link_delete_clients_ | bset
128 }
129 
130 // Check if the neighbor or link to neighbor should be filtered. Returns true
131 // if rnode or link to rnode should be filtered.
133  IFMapNode *rnode = link->left();
134  if (rnode == lnode)
135  rnode = link->right();
136  if (!traversal_white_list_->VertexFilter(rnode) ||
137  !traversal_white_list_->EdgeFilter(lnode, NULL, link)) {
138  return true;
139  }
140  return false;
141 }
142 
144  IFMapNode *node = static_cast<IFMapNode *>(vertex);
145  IFMapNodeState *state = exporter_->NodeStateLocate(node);
146  state->nmask_set(bit);
147  UpdateNewReachableNodesTracker(bit, state);
148 }
149 
151  if (link_delete_clients_.empty()) {
153  return true;
154  }
155 
156  IFMapServer *server = exporter_->server();
157  size_t i;
158 
159  // Get the index of the client we want to start with.
162  } else {
163  // walk_client_index_ was the last client that we finished processing.
165  }
166  int count = 0;
167  BitSet done_set;
168  while (i != BitSet::npos) {
169  IFMapClient *client = server->GetClient(i);
170  assert(client);
172 
173  IFMapTable *table = IFMapTable::FindTable(server->database(),
174  "virtual-router");
175  IFMapNode *node = table->FindNode(client->identifier());
176  if ((node != NULL) && node->IsVertexValid()) {
177  graph_->Visit(node,
178  [this, i](DBGraphVertex *v) { RecomputeInterest(v, i); },
179  0, *traversal_white_list_.get());
180  }
181  done_set.set(i);
182  if (++count == kMaxLinkDeleteWalks) {
183  // client 'i' has been processed. If 'i' is the last bit set, we
184  // will return true below. Else we will return false and there
185  // is atleast one more bit left to process.
186  break;
187  }
188 
190  }
191  // Remove the subset of clients that we have finished processing.
192  ResetLinkDeleteClients(done_set);
193 
194  LinkDeleteWalkBatchEnd(done_set);
195 
196  if (link_delete_clients_.empty()) {
198  return true;
199  } else {
200  walk_client_index_ = i;
201  return false;
202  }
203 }
204 
206  link_delete_clients_.Set(bset); // link_delete_clients_ | bset
207 }
208 
211 }
212 
213 void IFMapGraphWalker::CleanupInterest(int client_index, IFMapNode *node,
214  IFMapNodeState *state) {
215  BitSet rm_mask;
216  rm_mask.set(client_index);
217 
218  // interest = interest - rm_mask + nmask
219 
220  if (!state->interest().empty() && !state->nmask().empty()) {
222  state->interest().ToString(), rm_mask.ToString(),
223  state->nmask().ToString());
224  }
225  BitSet ninterest;
226  ninterest.BuildComplement(state->interest(), rm_mask);
227  ninterest |= state->nmask();
228  state->nmask_clear();
229  if (state->interest() == ninterest) {
230  return;
231  }
232 
233  exporter_->StateInterestSet(state, ninterest);
234  node->table()->Change(node);
235 
236  // Mark all dependent links as potentially modified.
237  for (IFMapNodeState::iterator iter = state->begin();
238  iter != state->end(); ++iter) {
239  DBTable *table = exporter_->link_table();
240  table->Change(iter.operator->());
241  }
242 }
243 
244 // Cleanup all the graph nodes that were reachable before this link delete.
245 // After this link delete, these nodes may still be reachable. But, its
246 // also possible that the link delete has made them unreachable.
248  IFMapState *state = NULL;
249  IFMapNode *node = NULL;
251  IFMapExporter::INTEREST, client_index);
253  IFMapExporter::INTEREST, client_index);
254 
255  while (iter != end_iter) {
256  state = *iter;
257  // Get the iterator to the next element before calling
258  // CleanupInterest() since the state might be removed from the
259  // client's config-tracker, thereby invalidating the iterator of the
260  // container we are iterating over.
261  ++iter;
262  if (state->IsNode()) {
263  node = state->GetIFMapNode();
264  assert(node);
265  IFMapNodeState *nstate = exporter_->NodeStateLookup(node);
266  assert(state == nstate);
267  CleanupInterest(client_index, node, nstate);
268  }
269  }
270 }
271 
272 // Cleanup all the graph nodes that were not reachable before the link delete
273 // but are reachable now. Note, we store nodes in new_reachable_nodes_tracker_
274 // only if we visited them during the graph-walk via RecomputeInterest() and if
275 // their interest bit was not set i.e. they were not reachable before we
276 // started the walk.
278  IFMapState *state = NULL;
279  IFMapNode *node = NULL;
280  ReachableNodesSet *rnset = new_reachable_nodes_tracker_.at(client_index);
281 
282  for (Rns_citer iter = rnset->begin(); iter != rnset->end(); ++iter) {
283  state = *iter;
284  assert(state->IsNode());
285  node = state->GetIFMapNode();
286  assert(node);
287  IFMapNodeState *nstate = exporter_->NodeStateLookup(node);
288  assert(state == nstate);
289  CleanupInterest(client_index, node, nstate);
290  }
291  DeleteNewReachableNodesTracker(client_index);
292 }
293 
295  for (size_t i = done_set.find_first(); i != BitSet::npos;
296  i = done_set.find_next(i)) {
297  // Examine all the nodes that were reachable before the link delete.
299  // Examine all the nodes that were not reachable before the link
300  // delete but are now reachable.
302  }
303 }
304 
306  if (client_index >= (int)new_reachable_nodes_tracker_.size()) {
307  new_reachable_nodes_tracker_.resize(client_index + 1, NULL);
308  }
309  assert(new_reachable_nodes_tracker_[client_index] == NULL);
310  ReachableNodesSet *rnset = new ReachableNodesSet();
311  new_reachable_nodes_tracker_[client_index] = rnset;
312 }
313 
315  ReachableNodesSet *rnset = new_reachable_nodes_tracker_.at(client_index);
316  assert(rnset);
317  delete rnset;
318  new_reachable_nodes_tracker_[client_index] = NULL;
319 }
320 
321 // Keep track of this node if it was unreachable earlier.
323  IFMapState *state) {
324  ReachableNodesSet *rnset = new_reachable_nodes_tracker_.at(client_index);
325  assert(rnset);
326  // If the interest is not set, the node was not reachable earlier but is
327  // reachable now.
328  if (!state->interest().test(client_index)) {
329  rnset->insert(state);
330  }
331 }
332 
334  const {
335  return *traversal_white_list_.get();
336 }
337 
338 // The nodes listed below and the nodes in
339 // IFMapGraphTraversalFilterCalculator::CreateNodeBlackList() are mutually
340 // exclusive
342  traversal_white_list_->include_vertex = {
343  {"virtual-router", {
344  "physical-router-virtual-router",
345  "virtual-router-virtual-machine",
346  "virtual-router-network-ipam",
347  "global-system-config-virtual-router",
348  "provider-attachment-virtual-router",
349  "virtual-router-virtual-machine-interface",
350  "virtual-router-sub-cluster",
351  }},
352  {"virtual-router-network-ipam", {
353  "virtual-router-network-ipam",
354  }},
355  {"virtual-machine", {
356  "virtual-machine-service-instance",
357  "virtual-machine-interface-virtual-machine",
358  "virtual-machine-tag",
359  }},
360  {"control-node-zone", {}},
361  {"sub-cluster", {
362  "bgp-router-sub-cluster",
363  }},
364  {"bgp-router", {
365  "instance-bgp-router",
366  "physical-router-bgp-router",
367  "bgp-router-control-node-zone",
368  }},
369  {"bgp-as-a-service", {
370  "bgpaas-bgp-router",
371  "bgpaas-health-check",
372  "bgpaas-control-node-zone",
373  }},
374  {"bgpaas-control-node-zone", {
375  "bgpaas-control-node-zone",
376  }},
377  {"global-system-config", {
378  "global-system-config-global-vrouter-config",
379  "global-system-config-global-qos-config",
380  "global-system-config-bgp-router",
381  "qos-config-global-system-config",
382  }},
383  {"provider-attachment", {}},
384  {"service-instance", {
385  "service-instance-service-template",
386  "service-instance-port-tuple",
387  }},
388  {"global-vrouter-config", {
389  "application-policy-set-global-vrouter-config",
390  "global-vrouter-config-security-logging-object",
391  }},
392  {"virtual-machine-interface", {
393  "virtual-machine-virtual-machine-interface",
394  "virtual-machine-interface-sub-interface",
395  "instance-ip-virtual-machine-interface",
396  "virtual-machine-interface-virtual-network",
397  "virtual-machine-interface-security-group",
398  "floating-ip-virtual-machine-interface",
399  "alias-ip-virtual-machine-interface",
400  "customer-attachment-virtual-machine-interface",
401  "virtual-machine-interface-routing-instance",
402  "virtual-machine-interface-route-table",
403  "subnet-virtual-machine-interface",
404  "service-port-health-check",
405  "bgpaas-virtual-machine-interface",
406  "virtual-machine-interface-qos-config",
407  "virtual-machine-interface-bridge-domain",
408  "virtual-machine-interface-security-logging-object",
409  "project-virtual-machine-interface",
410  "port-tuple-interface",
411  "virtual-machine-interface-tag",
412  "virtual-machine-interface-bgp-router",
413  }},
414  {"virtual-machine-interface-bridge-domain", {
415  "virtual-machine-interface-bridge-domain",
416  }},
417  {"security-group", {
418  "security-group-access-control-list",
419  }},
420  {"physical-router", {
421  "physical-router-physical-interface",
422  "physical-router-logical-interface",
423  "physical-router-virtual-network",
424  }},
425  {"service-template", {
426  "domain-service-template",
427  }},
428  {"instance-ip", {
429  "instance-ip-virtual-network",
430  }},
431  {"virtual-network", {
432  "virtual-network-floating-ip-pool",
433  "virtual-network-alias-ip-pool",
434  "virtual-network-network-ipam",
435  "virtual-network-access-control-list",
436  "virtual-network-routing-instance",
437  "virtual-network-qos-config",
438  "virtual-network-bridge-domain",
439  "virtual-network-security-logging-object",
440  "virtual-network-tag",
441  "virtual-network-provider-network",
442  "virtual-network-multicast-policy",
443  "vn-health-check",
444  "host-based-service-virtual-network",
445  "project-virtual-network",
446  }},
447  {"floating-ip", {
448  "floating-ip-pool-floating-ip",
449  "instance-ip-floating-ip",
450  }},
451  {"alias-ip", {
452  "alias-ip-pool-alias-ip",
453  }},
454  {"customer-attachment", {}},
455  {"virtual-machine-interface-routing-instance", {
456  "virtual-machine-interface-routing-instance",
457  }},
458  {"physical-interface", {
459  "physical-interface-logical-interface",
460  "virtual-port-group-physical-interface",
461  }},
462  {"virtual-port-group-physical-interface", {
463  "virtual-port-group-physical-interface",
464  }},
465  {"virtual-port-group", {
466  "virtual-port-group-virtual-machine-interface",
467  "virtual-port-group-physical-interface",
468  }},
469  {"domain", {
470  "domain-namespace",
471  "domain-virtual-DNS",
472  }},
473  {"floating-ip-pool", {
474  "virtual-network-floating-ip-pool",
475  }},
476  {"alias-ip-pool", {
477  "virtual-network-alias-ip-pool",
478  }},
479  {"logical-interface", {
480  "logical-interface-virtual-machine-interface",
481  }},
482  {"logical-router-virtual-network", {
483  "logical-router-virtual-network",
484  }},
485  {"logical-router", {
486  "logical-router-virtual-network",
487  "logical-router-interface",
488  }},
489  {"virtual-network-network-ipam", {
490  "virtual-network-network-ipam",
491  }},
492  {"access-control-list", {}},
493  {"routing-instance", {}},
494  {"namespace", {}},
495  {"virtual-DNS", {
496  "virtual-DNS-virtual-DNS-record",
497  }},
498  {"network-ipam", {
499  "network-ipam-virtual-DNS",
500  }},
501  {"virtual-DNS-record", {}},
502  {"interface-route-table", {}},
503  {"subnet", {}},
504  {"service-health-check", {}},
505  {"qos-config", {}},
506  {"qos-queue", {}},
507  {"forwarding-class", {
508  "forwarding-class-qos-queue",
509  }},
510  {"global-qos-config", {
511  "global-qos-config-forwarding-class",
512  "global-qos-config-qos-queue",
513  "global-qos-config-qos-config",
514  }},
515  {"bridge-domain", {}},
516  {"security-logging-object", {
517  "virtual-network-security-logging-object",
518  "virtual-machine-interface-security-logging-object",
519  "global-vrouter-config-security-logging-object",
520  "security-logging-object-network-policy",
521  "security-logging-object-security-group",
522  }},
523  {"tag", {
524  "application-policy-set-tag",
525  }},
526  {"application-policy-set", {
527  "application-policy-set-firewall-policy",
528  "policy-management-application-policy-set",
529  }},
530  {"application-policy-set-firewall-policy", {
531  "application-policy-set-firewall-policy",
532  }},
533  {"firewall-policy", {
534  "firewall-policy-firewall-rule",
535  "firewall-policy-security-logging-object",
536  }},
537  {"firewall-policy-firewall-rule", {
538  "firewall-policy-firewall-rule",
539  }},
540  {"firewall-policy-security-logging-object", {
541  "firewall-policy-security-logging-object",
542  }},
543  {"firewall-rule", {
544  "firewall-rule-tag",
545  "firewall-rule-service-group",
546  "firewall-rule-address-group",
547  "firewall-rule-security-logging-object",
548  }},
549  {"firewall-rule-security-logging-object", {
550  "firewall-rule-security-logging-object",
551  }},
552  {"service-group", {}},
553  {"address-group", {
554  "address-group-tag",
555  }},
556  {"host-based-service", {
557  "host-based-service-virtual-network",
558  }},
559  {"host-based-service-virtual-network", {
560  "virtual-network",
561  }},
562  {"project", {
563  "project-tag",
564  "project-logical-router",
565  "project-host-based-service",
566  }},
567  {"port-tuple", {
568  "service-instance-port-tuple",
569  "port-tuple-interface",
570  }},
571  {"policy-management", {}},
572  {"multicast-policy", {
573  "virtual-network-multicast-policy",
574  }},
575  };
576 }
577 
Definition: bitset.h:17
void Set(const BitSet &rhs)
Definition: bitset.cc:462
static const size_t npos
Definition: bitset.h:19
size_t find_first() const
Definition: bitset.cc:242
void BuildComplement(const BitSet &lhs, const BitSet &rhs)
Definition: bitset.cc:486
void Reset(const BitSet &rhs)
Definition: bitset.cc:470
size_t find_next(size_t pos) const
Definition: bitset.cc:255
bool empty() const
Definition: bitset.cc:165
bool Contains(const BitSet &rhs) const
Definition: bitset.cc:536
BitSet & set(size_t pos)
Definition: bitset.cc:125
bool test(size_t pos) const
Definition: bitset.cc:146
std::string ToString() const
Definition: bitset.cc:551
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
virtual std::string ToString() const =0
void Visit(DBGraphVertex *start, VertexVisitor vertex_visit_fn, EdgeVisitor edge_visit_fn)
Definition: db_graph.cc:111
virtual void Change(DBEntryBase *entry)
Definition: db_table.cc:433
DBGraph::VisitorFilter::AllowedEdgeRetVal AllowedEdges(const DBGraphVertex *vertex) const
bool EdgeFilter(const DBGraphVertex *source, const DBGraphVertex *target, const DBGraphEdge *edge) const
GraphPropagateFilter(IFMapExporter *exporter, const IFMapTypenameWhiteList *type_filter, const BitSet &bitset)
bool VertexFilter(const DBGraphVertex *vertex) const
const IFMapNodeState * NodeStateLookup(const IFMapNode *node) const
const IFMapTypenameWhiteList * type_filter_
IFMapExporter * exporter_
virtual const std::string & identifier() const =0
int index() const
Definition: ifmap_client.h:31
Cs_citer ClientConfigTrackerEnd(TrackerType tracker_type, int index) const
IFMapServer * server()
void StateInterestOr(IFMapState *state, const BitSet &interest_bits)
Cs_citer ClientConfigTrackerBegin(TrackerType tracker_type, int index) const
DBTable * link_table()
void StateInterestSet(IFMapState *state, const BitSet &interest_bits)
ConfigSet::const_iterator Cs_citer
DBTable::ListenerId TableListenerId(const DBTable *table) const
IFMapNodeState * NodeStateLookup(IFMapNode *node)
IFMapNodeState * NodeStateLocate(IFMapNode *node)
std::set< IFMapState * > ReachableNodesSet
void JoinVertex(DBGraphVertex *vertex, const BitSet &bset)
void OrLinkDeleteClients(const BitSet &bset)
void UpdateNewReachableNodesTracker(int client_index, IFMapState *state)
const IFMapTypenameWhiteList & get_traversal_white_list() const
void LinkAdd(IFMapLink *link, IFMapNode *lnode, const BitSet &lhs, IFMapNode *rnode, const BitSet &rhs)
void NotifyEdge(DBGraphEdge *edge, const BitSet &bset)
ReachableNodesTracker new_reachable_nodes_tracker_
void LinkDeleteWalkBatchEnd(const BitSet &done_set)
ReachableNodesSet::const_iterator Rns_citer
IFMapGraphWalker(DBGraph *graph, IFMapExporter *exporter)
boost::scoped_ptr< TaskTrigger > link_delete_walk_trigger_
IFMapExporter * exporter_
void NewReachableNodesCleanupInterest(int client_index)
void OldReachableNodesCleanupInterest(int client_index)
void LinkRemove(const BitSet &bset)
static const int kMaxLinkDeleteWalks
void ProcessLinkAdd(IFMapNode *lnode, IFMapNode *rnode, const BitSet &bset)
bool FilterNeighbor(IFMapNode *lnode, IFMapLink *link)
void DeleteNewReachableNodesTracker(int client_index)
void CleanupInterest(int client_index, IFMapNode *node, IFMapNodeState *state)
void AddNewReachableNodesTracker(int client_index)
void ResetLinkDeleteClients(const BitSet &bset)
void RecomputeInterest(DBGraphVertex *vertex, int bit)
std::unique_ptr< IFMapTypenameWhiteList > traversal_white_list_
void nmask_set(int bit)
Definition: ifmap_update.h:195
iterator end()
Definition: ifmap_update.h:188
iterator begin()
Definition: ifmap_update.h:187
void nmask_clear()
Definition: ifmap_update.h:194
const BitSet & nmask() const
Definition: ifmap_update.h:193
IFMapTable * table()
Definition: ifmap_node.h:29
virtual std::string ToString() const
Definition: ifmap_node.cc:31
DB * database()
Definition: ifmap_server.h:82
IFMapClient * GetClient(int index)
bool IsNode() const
Definition: ifmap_update.h:159
const BitSet & interest() const
Definition: ifmap_update.h:129
IFMapNode * GetIFMapNode() const
static IFMapTable * FindTable(DB *db, const std::string &element_type)
Definition: ifmap_table.cc:39
IFMapNode * FindNode(const std::string &name)
Definition: ifmap_table.cc:23
int GetTaskId(const std::string &name)
Definition: task.cc:861
static TaskScheduler * GetInstance()
Definition: task.cc:554
#define IFMAP_DEBUG(obj,...)
Definition: ifmap_log.h:33
std::pair< bool, AllowedEdgeSet > AllowedEdgeRetVal
Definition: db_graph.h:30
virtual AllowedEdgeRetVal AllowedEdges(const DBGraphVertex *source) const
Definition: ifmap_util.cc:55
virtual bool VertexFilter(const DBGraphVertex *vertex) const
Definition: ifmap_util.cc:46