OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
config_listener.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "cfg/config_listener.h"
6 
7 #include <boost/assign/list_of.hpp>
8 #include <boost/bind.hpp>
9 #include "bind/bind_util.h"
10 #include "cfg/dns_config.h"
11 #include "db/db.h"
12 #include "db/db_table_partition.h"
13 #include "ifmap/ifmap_link.h"
14 #include "ifmap/ifmap_node.h"
15 #include "ifmap/ifmap_table.h"
16 
17 using namespace boost::assign;
18 using namespace std;
19 
20 // The DependencyTracker adds elements onto the change list that must be
21 // reevaluated when links are added or deleted from the graph.
23 public:
24  struct EdgeDescriptor {
25  EdgeDescriptor(const string &meta, const string &type,
26  const string &name)
27  : metadata(meta), id_type(type), id_name(name) {
28  }
29  string metadata;
30  string id_type;
31  string id_name;
32  };
33  typedef list<EdgeDescriptor> EdgeDescriptorList;
34  typedef list<pair<string, string> > NodeList;
35 
36  // identifier type -> (incoming, outlist)
37  typedef set<string> PropagateList;
38  typedef map<string, PropagateList> ReactionMap;
39  typedef map<string, ReactionMap> NodeEventPolicy;
40 
41  DependencyTracker(ConfigListener *listener) : listener_(listener) {
42  Initialize();
43  }
44 
45  void Initialize() {
46  ReactionMap ipam_react =
47  map_list_of<string, PropagateList>
48  ("self", list_of("self").convert_to_container<PropagateList>())
49  ("virtual-network-network-ipam", list_of("self")
50  .convert_to_container<PropagateList>());
51  policy_.insert(make_pair("network-ipam", ipam_react));
52 #if 0
53  ReactionMap vnni_react =
54  map_list_of<string, PropagateList>
55  ("self", list_of("self"))
56  ("network-ipam", list_of("self"))
57  ("virtual-network-network-ipam", list_of("self"));
58  policy_.insert(make_pair("virtual-network-network-ipam", vnni_react));
59 #endif
60  ReactionMap virt_dns_react =
61  map_list_of<string, PropagateList>
62  ("self", list_of("self"));
63  policy_.insert(make_pair("virtual-DNS", virt_dns_react));
64  ReactionMap virt_dns_rec_react =
65  map_list_of<string, PropagateList>
66  ("self", list_of("self").convert_to_container<PropagateList>())
67  ("virtual-DNS-virtual-DNS-record", list_of("self")
68  .convert_to_container<PropagateList>());
69  policy_.insert(make_pair("virtual-DNS-record", virt_dns_rec_react));
70  }
71 
72  void NodeEvent(IFMapNode *node) {
73  ostringstream identifier;
74  identifier << node->table()->Typename() << ':' << node->name();
75  vertex_list_.insert(identifier.str());
76  if (IsInterestingEvent(node, "self")) {
77  node_list_.push_back(
78  make_pair(node->table()->Typename(), node->name()));
79  }
80  }
81 
82  bool LinkEvent(const string metadata,
83  IFMapNode *left, IFMapNode *right) {
84  bool interest = false;
85  if ((left != NULL) && IsInterestingEvent(left, metadata)) {
86  const char *type_left = left->table()->Typename();
87  edge_list_.push_back(
88  EdgeDescriptor(metadata, type_left, left->name()));
89  interest = true;
90  }
91  if ((right != NULL) && IsInterestingEvent(right, metadata)) {
92  const char *type_right = right->table()->Typename();
93  edge_list_.push_back(
94  EdgeDescriptor(metadata, type_right, right->name()));
95  interest = true;
96  }
97  return interest;
98  }
99 
100  void PropagateChanges(ChangeList *change_list) {
101  InEdgeSet in_edges;
102 
103  for (NodeList::iterator iter = node_list_.begin();
104  iter != node_list_.end(); ++iter) {
105  IFMapTable *table = IFMapTable::FindTable(listener_->database(),
106  iter->first);
107  if (table == NULL) {
108  continue;
109  }
110  IFMapNode *node = table->FindNode(iter->second);
111  if ((node == NULL) || node->IsDeleted()) {
112  continue;
113  }
114  PropagateNode(node, &in_edges, change_list);
115  }
116 
117  for (EdgeDescriptorList::iterator iter = edge_list_.begin();
118  iter != edge_list_.end(); ++iter) {
119  const EdgeDescriptor &edge = *iter;
120  IFMapTable *table = IFMapTable::FindTable(listener_->database(),
121  edge.id_type);
122  if (table == NULL) {
123  continue;
124  }
125  IFMapNode *node = table->FindNode(edge.id_name);
126  if ((node == NULL) || node->IsDeleted()) {
127  continue;
128  }
129  PropagateEdge(node, edge.metadata, &in_edges, change_list);
130  }
131  }
132 
133  void Clear() {
134  vertex_list_.clear();
135  node_list_.clear();
136  edge_list_.clear();
137  }
138 
139 private:
140  typedef set<pair<IFMapNode *, string> > InEdgeSet;
141 
142  const PropagateList *GetPropagateList(const string &type,
143  const string &metadata) const {
144  NodeEventPolicy::const_iterator loc = policy_.find(type);
145  if (loc == policy_.end()) {
146  return NULL;
147  }
148  ReactionMap::const_iterator react = loc->second.find(metadata);
149  if (react == loc->second.end()) {
150  return NULL;
151  }
152  return &react->second;
153  }
154 
155  bool IsInterestingEvent(const IFMapNode *node,
156  const string &metadata) const {
157  if (node->IsDeleted()) {
158  return false;
159  }
160  return GetPropagateList(node->table()->Typename(), metadata) != NULL;
161  }
162 
163  void PropagateNode(IFMapNode *node, InEdgeSet *in_edges,
164  ChangeList *change_list) {
165  // iterate through the edges of node.
166  for (DBGraphVertex::edge_iterator iter =
167  node->edge_list_begin(listener_->graph());
168  iter != node->edge_list_end(listener_->graph()); ++iter) {
169  IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
170  IFMapNode *target = static_cast<IFMapNode *>(iter.target());
171  const PropagateList *plist = GetPropagateList(
172  target->table()->Typename(), link->metadata());
173  if (plist == NULL) {
174  continue;
175  }
176  PropagateEdge(target, link->metadata(), in_edges, change_list);
177  }
178  }
179 
180  void PropagateEdge(IFMapNode *node, const string &metadata,
181  InEdgeSet *in_edges, ChangeList *change_list) {
182  const PropagateList *plist = GetPropagateList(node->table()->Typename(),
183  metadata);
184  if (plist == NULL) {
185  return;
186  }
187  assert(!node->IsDeleted());
188  in_edges->insert(make_pair(node, metadata));
189 
190  PropagateList::const_iterator self = plist->find("self");
191  if (self != plist->end()) {
192  AddChangeEvent(change_list, node);
193  }
194 
195  // iterate through the edges of node.
196  for (DBGraphVertex::edge_iterator iter =
197  node->edge_list_begin(listener_->graph());
198  iter != node->edge_list_end(listener_->graph()); ++iter) {
199  IFMapLink *link = static_cast<IFMapLink *>(iter.operator->());
200  PropagateList::const_iterator p_edge =
201  plist->find(link->metadata());
202  if (p_edge == plist->end()) {
203  continue;
204  }
205  IFMapNode *target = static_cast<IFMapNode *>(iter.target());
206  if (in_edges->count(make_pair(target, link->metadata())) > 0) {
207  continue;
208  }
209  PropagateEdge(target, link->metadata(), in_edges, change_list);
210  }
211  }
212 
213  void AddChangeEvent(ChangeList *change_list, IFMapNode *node) {
214  ostringstream identifier;
215  identifier << node->table()->Typename() << ':' << node->name();
216  if (vertex_list_.count(identifier.str()) > 0) {
217  return;
218  }
219  listener_->ChangeListAdd(change_list, node);
220  vertex_list_.insert(identifier.str());
221  }
222 
225  set<string> vertex_list_;
228 };
229 
231  : manager_(manager), tracker_(new DependencyTracker(this)) {
232 }
233 
235 }
236 
237 void ConfigListener::Initialize(DB *database, int ntypes,
238  const char *config_types[]) {
239  DBTable *link_table = static_cast<DBTable *>(
240  database->FindTable("__ifmap_metadata__.0"));
241  assert(link_table != NULL);
242  DBTable::ListenerId id = link_table->Register(
243  boost::bind(&ConfigListener::LinkObserver, this, _1, _2));
244  table_map_.insert(make_pair(link_table->name(), id));
245 
246  for (int i = 0; i < ntypes; i++) {
247  const char *type_name = config_types[i];
248  IFMapTable *table = IFMapTable::FindTable(database, type_name);
249  assert(table);
250  DBTable::ListenerId id = table->Register(
251  boost::bind(&ConfigListener::NodeObserver, this, _1, _2));
252  table_map_.insert(make_pair(table->name(), id));
253  }
254 }
255 
256 void ConfigListener::Terminate(DB *database) {
257  for (TableMap::iterator iter = table_map_.begin(); iter != table_map_.end();
258  ++iter) {
259  IFMapTable *table = static_cast<IFMapTable *>(
260  database->FindTable(iter->first));
261  assert(table);
262  table->Unregister(iter->second);
263  }
264  table_map_.clear();
265 }
266 
268  return manager_->database();
269 }
270 
272  return manager_->graph();
273 }
274 
276  tracker_->PropagateChanges(&change_list_);
277  tracker_->Clear();
278  change_list->swap(change_list_);
279 }
280 
282  IFMapNode *node) const {
283  IFMapTable *table = node->table();
284  TableMap::const_iterator tid = table_map_.find(table->name());
285  if (tid == table_map_.end()) {
286  return;
287  }
288 
289  ConfigDelta delta;
290  delta.id_type = table->Typename();
291  delta.id_name = node->name();
292  if (!node->IsDeleted()) {
293 
294  DBState *current = node->GetState(table, tid->second);
295  if (current == NULL) {
296  delta.node = IFMapNodeProxyRef(new IFMapNodeProxy(node, tid->second));
297  }
298  delta.obj = IFMapObjectRef(node->GetObject());
299  }
300  change_list->push_back(delta);
301 }
302 
304  DBEntryBase *db_entry) {
305  IFMapNode *node = static_cast<IFMapNode *>(db_entry);
306  // Ignore deleted nodes for which the configuration code doesn't hold state.
307  if (node->IsDeleted()) {
308  IFMapTable *table = node->table();
309  TableMap::const_iterator tid = table_map_.find(table->name());
310  assert(tid != table_map_.end());
311  if (node->GetState(table, tid->second) == NULL) {
312  return;
313  }
314  }
315  ChangeListAdd(&change_list_, node);
316  tracker_->NodeEvent(node);
317  manager_->OnChange();
318 }
319 
321  DBEntryBase *db_entry) {
322  IFMapLink *link = static_cast<IFMapLink *>(db_entry);
323  IFMapNode *left = link->LeftNode(database());
324  IFMapNode *right = link->RightNode(database());
325  if (tracker_->LinkEvent(link->metadata(), left, right)) {
326  manager_->OnChange();
327  }
328 }
boost::shared_ptr< IFMapNodeProxy > IFMapNodeProxyRef
Definition: dns_config.h:39
map< string, ReactionMap > NodeEventPolicy
list< EdgeDescriptor > EdgeDescriptorList
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
void LinkObserver(DBTablePartBase *root, DBEntryBase *db_entry)
void ChangeListAdd(ChangeList *change_list, IFMapNode *node) const
void PropagateEdge(IFMapNode *node, const string &metadata, InEdgeSet *in_edges, ChangeList *change_list)
void PropagateNode(IFMapNode *node, InEdgeSet *in_edges, ChangeList *change_list)
bool IsDeleted() const
Definition: db_entry.h:49
set< pair< IFMapNode *, string > > InEdgeSet
void Terminate(DB *database)
int ListenerId
Definition: db_table.h:62
void Initialize(DB *database, int ntypes, const char *config_types[])
void AddChangeEvent(ChangeList *change_list, IFMapNode *node)
virtual const char * Typename() const =0
std::vector< ConfigDelta > ChangeList
IFMapTable * table()
Definition: ifmap_node.h:29
boost::intrusive_ptr< IFMapObject > IFMapObjectRef
Definition: ifmap_object.h:58
std::string id_type
Definition: dns_config.h:45
void Unregister(ListenerId listener)
Definition: db_table.cc:186
DBGraph * graph()
TableMap table_map_
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
ChangeList change_list_
Definition: db.h:24
virtual ~ConfigListener()
void NodeObserver(DBTablePartBase *root, DBEntryBase *db_entry)
const PropagateList * GetPropagateList(const string &type, const string &metadata) const
uint8_t type
Definition: load_balance.h:109
void GetChangeList(ChangeList *change_list)
IFMapNode * FindNode(const std::string &name)
Definition: ifmap_table.cc:23
DnsConfigManager * manager_
const std::string & name() const
Definition: db_table.h:110
DependencyTracker(ConfigListener *listener)
const std::string & name() const
Definition: ifmap_node.h:48
void PropagateChanges(ChangeList *change_list)
ConfigListener(DnsConfigManager *manager)
IFMapObjectRef obj
Definition: dns_config.h:48
IFMapObject * GetObject()
Definition: ifmap_node.cc:63
static IFMapTable * FindTable(DB *db, const std::string &element_type)
Definition: ifmap_table.cc:39
bool IsInterestingEvent(const IFMapNode *node, const string &metadata) const
map< string, PropagateList > ReactionMap
DBGraph * graph()
Definition: dns_config.h:101
edge_iterator edge_list_end(DBGraph *graph)
bool LinkEvent(const string metadata, IFMapNode *left, IFMapNode *right)
IFMapNodeProxyRef node
Definition: dns_config.h:47
std::string id_name
Definition: dns_config.h:46
list< pair< string, string > > NodeList
EdgeDescriptor(const string &meta, const string &type, const string &name)
boost::scoped_ptr< DependencyTracker > tracker_
DBTableBase * FindTable(const std::string &name)
Definition: db.cc:68
edge_iterator edge_list_begin(DBGraph *graph)