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