OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ha_stale_dev_vn.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 extern "C" {
6 #include <ovsdb_wrapper.h>
7 };
9 #include <ovsdb_client.h>
10 #include <ovsdb_route_peer.h>
12 #include <ha_stale_dev_vn.h>
13 #include <ha_stale_vn.h>
14 #include <ha_stale_l2_route.h>
16 #include <oper/vn.h>
17 #include <oper/vrf.h>
18 #include <oper/nexthop.h>
19 #include <oper/tunnel_nh.h>
20 #include <oper/agent_path.h>
21 #include <oper/bridge_route.h>
22 
23 #include <ovsdb_sandesh.h>
24 #include <ovsdb_types.h>
25 
26 using namespace OVSDB;
27 
29  const boost::uuids::uuid &vn_uuid) : OvsdbDBEntry(table),
30  vn_uuid_(vn_uuid), l2_table_(NULL), old_l2_table_(NULL),
31  oper_bridge_table_(NULL), dev_ip_(), vn_name_(""), vxlan_id_(0) {
32 }
33 
35  assert(l2_table_ == NULL);
36  assert(old_l2_table_ == NULL);
37 }
38 
40  // if table is scheduled for delete, return from here
41  // and wait for delete callback
42  if (table_->delete_scheduled()) {
43  return true;
44  }
45 
46  bool ret = true;
47  // On device ip, vxlan id or Agent Route Table pointer change delete
48  // previous route table and add new with updated vxlan id
49  if (l2_table_ != NULL &&
51  ret = Delete();
52  }
53 
54  // create route table and register
55  if (l2_table_ == NULL) {
57  }
58 
59  // trigger update params for L2 Table to pick new vxlan id / tor ip
60  l2_table_->UpdateParams(this);
61  return ret;
62 }
63 
65  return Add();
66 }
67 
69  // delete route table.
70  if (l2_table_ != NULL) {
72  assert(old_l2_table_ == NULL);
74  l2_table_ = NULL;
75  return false;
76  }
77 
78  return true;
79 }
80 
82  bool change = false;
83  // check if route table is available.
84  const PhysicalDeviceVn *dev_vn =
85  static_cast<const PhysicalDeviceVn *>(db_entry);
86  const VrfEntry *vrf = dev_vn->vn()->GetVrf();
87  if (vrf == NULL) {
88  // trigger change and wait for VRF
89  oper_bridge_table_ = NULL;
90  change = true;
91  } else if (oper_bridge_table_ != vrf->GetBridgeRouteTable()) {
93  change = true;
94  }
95  if (dev_ip_ != dev_vn->tor_ip()) {
96  dev_ip_ = dev_vn->tor_ip();
97  change = true;
98  }
99  if (vn_name_ != dev_vn->vn()->GetName()) {
100  vn_name_ = dev_vn->vn()->GetName();
101  change = true;
102  }
103  if (vxlan_id_ != (uint32_t)dev_vn->vxlan_id()) {
104  vxlan_id_ = dev_vn->vxlan_id();
105  change = true;
106  }
107  return change;
108 }
109 
110 bool HaStaleDevVnEntry::IsLess(const KSyncEntry &entry) const {
111  const HaStaleDevVnEntry &dev_vn_entry =
112  static_cast<const HaStaleDevVnEntry &>(entry);
113  return vn_uuid_ < dev_vn_entry.vn_uuid_;
114 }
115 
118  static_cast<HaStaleDevVnTable *>(table_);
119  HaStaleVnEntry key(table->vn_table_, vn_uuid_);
120  HaStaleVnEntry *entry = static_cast<HaStaleVnEntry*>
121  (table->vn_table_->GetReference(&key));
122  // Wait for vn-vrf link
123  if (!entry->IsResolved()) {
124  return entry;
125  }
126 
127  if (oper_bridge_table_ == NULL) {
128  // update route table when vn-vrf link is available
129  oper_bridge_table_ = entry->bridge_table();
130  }
131 
132  if (vn_name_.empty()) {
133  // update vn name from vn if available
134  vn_name_ = entry->vn_name();
135  }
136  return NULL;
137 }
138 
140  OvsdbDBObject *object = static_cast<OvsdbDBObject*>(GetObject());
141  assert(old_l2_table_ == table);
142  if (l2_table_ != NULL) {
143  old_l2_table_ = NULL;
144  object->SafeNotifyEvent(this, KSyncEntry::ADD_ACK);
145  } else {
146  old_l2_table_ = NULL;
147  object->SafeNotifyEvent(this, KSyncEntry::DEL_ACK);
148  }
149 }
150 
152  const HaStaleDevVnTable *reflector_table =
153  static_cast<const HaStaleDevVnTable *>(table_);
154  return reflector_table->agent();
155 }
156 
158  const HaStaleDevVnTable *reflector_table =
159  static_cast<const HaStaleDevVnTable *>(table_);
160  return reflector_table->route_peer();
161 }
162 
163 const std::string &HaStaleDevVnEntry::dev_name() const {
164  const HaStaleDevVnTable *reflector_table =
165  static_cast<const HaStaleDevVnTable *>(table_);
166  return reflector_table->dev_name();
167 }
168 
170  const HaStaleDevVnTable *reflector_table =
171  static_cast<const HaStaleDevVnTable *>(table_);
172  return reflector_table->state();
173 }
174 
176  return dev_ip_;
177 }
178 
179 const std::string &HaStaleDevVnEntry::vn_name() const {
180  return vn_name_;
181 }
182 
183 uint32_t HaStaleDevVnEntry::vxlan_id() const {
184  return vxlan_id_;
185 }
186 
188  OvsPeerManager *manager, ConnectionStateEntry *state,
189  std::string &dev_name) :
190  OvsdbDBObject(NULL, false), agent_(agent), manager_(manager),
191  dev_name_(dev_name), state_(state),
192  vn_table_(new HaStaleVnTable(agent, this)), time_stamp_(1),
193  stale_clear_timer_(TimerManager::CreateTimer(
194  *(agent->event_manager())->io_service(),
195  "OVSDB Route Replicator cleanup timer",
196  agent->task_scheduler()->GetTaskId("Agent::KSync"), 0)) {
198  agent->task_scheduler()->GetTaskId("Agent::KSync"), 0,
199  boost::bind(&HaStaleDevVnTable::VnReEval, this, _1));
200  vn_reeval_queue_->set_name("OVSDB VN re-evaluation queue");
201  Ip4Address zero_ip;
202  route_peer_.reset(manager->Allocate(zero_ip));
203  route_peer_->set_ha_stale_export(true);
205 }
206 
208  // validate vn_table and vn_reeval_queue are deleted
209  // before the destuctor is called
210  assert(vn_table_ == NULL && vn_reeval_queue_ == NULL);
211 
212  // Cancel timer if running
215  manager_->Free(route_peer_.release());
216 }
217 
218 KSyncEntry *HaStaleDevVnTable::Alloc(const KSyncEntry *key, uint32_t index) {
219  const HaStaleDevVnEntry *k_entry =
220  static_cast<const HaStaleDevVnEntry *>(key);
221  HaStaleDevVnEntry *entry = new HaStaleDevVnEntry(this, k_entry->vn_uuid_);
222  return entry;
223 }
224 
226  const PhysicalDeviceVn *entry =
227  static_cast<const PhysicalDeviceVn *>(db_entry);
228  HaStaleDevVnEntry *key =
229  new HaStaleDevVnEntry(this, entry->vn()->GetUuid());
230  return static_cast<KSyncEntry *>(key);
231 }
232 
234  const DBEntry *entry, const OvsdbDBEntry *ovsdb_entry) {
235  const PhysicalDeviceVn *dev_vn =
236  static_cast<const PhysicalDeviceVn *>(entry);
237 
238  // Delete the entry which has invalid VxLAN id associated.
239  if (dev_vn->vxlan_id() == 0) {
240  return DBFilterDelete;
241  }
242 
243  // Accept only devices with name matched to dev_name_
244  if (dev_vn->device_display_name() != dev_name_) {
245  return DBFilterDelete;
246  }
247 
248  if (vn_table_ == NULL) {
249  // delete table delete notify the entry
250  return DBFilterDelete;
251  }
252 
253  return DBFilterAccept;
254 }
255 
257  return agent_;
258 }
259 
261  if (vn_table_ != NULL) {
263  vn_table_ = NULL;
264  }
265 
266  if (vn_reeval_queue_ != NULL) {
268  delete vn_reeval_queue_;
269  vn_reeval_queue_ = NULL;
270  }
271 }
272 
275  // unregister the object if emptytable is called with
276  // object being scheduled for delete
277  if (delete_scheduled()) {
279  }
280 }
281 
283  // vn_reeval_queue_ will be NULL if delete of the table
284  // is already triggered
285  if (vn_reeval_queue_ != NULL) {
286  vn_reeval_queue_->Enqueue(vn_uuid);
287  }
288 }
289 
291  HaStaleDevVnEntry key(this, vn_uuid);
292  HaStaleDevVnEntry *entry =
293  static_cast<HaStaleDevVnEntry*>(Find(&key));
294  if (entry && !entry->IsDeleted()) {
295  Change(entry);
296  }
297  return true;
298 }
299 
301  return route_peer_.get();
302 }
303 
304 const std::string &HaStaleDevVnTable::dev_name() const {
305  return dev_name_;
306 }
307 
309  return state_.get();
310 }
311 
312 void HaStaleDevVnTable::StaleClearAddEntry(uint64_t time_stamp,
313  HaStaleL2RouteEntry *entry,
314  StaleClearL2EntryCb cb) {
315  if (stale_l2_entry_map_.empty()) {
316  // start the timer while adding the first entry
318  boost::bind(&HaStaleDevVnTable::StaleClearTimerCb, this));
319  }
320  StaleL2Entry l2_entry(time_stamp, entry);
321  stale_l2_entry_map_[l2_entry] = cb;
322 }
323 
324 void HaStaleDevVnTable::StaleClearDelEntry(uint64_t time_stamp,
325  HaStaleL2RouteEntry *entry) {
326  StaleL2Entry l2_entry(time_stamp, entry);
327  stale_l2_entry_map_.erase(l2_entry);
328  if (stale_l2_entry_map_.empty()) {
329  // stop the timer on last entry removal
331  }
332 }
333 
335  uint32_t count = 0;
336  time_stamp_++;
337  uint32_t timer =
339  while (!stale_l2_entry_map_.empty() && count < kNumEntriesPerIteration) {
340  CbMap::iterator it = stale_l2_entry_map_.begin();
341  if (time_stamp_ - it->first.time_stamp < timer) {
342  // first entry is yet to age
343  break;
344  }
345  StaleClearL2EntryCb cb = it->second;
346  cb();
347  count++;
348  }
349 
350  if (stale_l2_entry_map_.empty()) {
351  // do not restart the timer if all entries are removed
352  return false;
353  }
354  return true;
355 }
356 
358 // Sandesh routines
361  std::string resp_ctx, AgentSandeshArguments &args) :
362  OvsdbSandeshTask(resp_ctx, args), dev_name_(""), vn_uuid_("") {
363  if (false == args.Get("dev_name", &dev_name_)) {
364  dev_name_ = "";
365  }
366  if (false == args.Get("vn_uuid", &vn_uuid_)) {
367  vn_uuid_ = "";
368  }
369 }
370 
372  const std::string &dev_name,
373  const std::string &vn_uuid) :
374  OvsdbSandeshTask(resp_ctx, "0.0.0.0", 0), dev_name_(dev_name), vn_uuid_(vn_uuid) {
375 }
376 
378 }
379 
381  if (!dev_name_.empty()) {
382  args.Add("dev_name", dev_name_);
383  }
384  if (!vn_uuid_.empty()) {
385  args.Add("vn_uuid", vn_uuid_);
386  }
387 }
388 
391  if (!vn_uuid_.empty()) {
392  HaStaleDevVnEntry *entry = static_cast<HaStaleDevVnEntry *>(kentry);
393  if (UuidToString(entry->vn_uuid()).find(vn_uuid_) != std::string::npos) {
394  return FilterAllow;
395  }
396  return FilterDeny;
397  }
398  return FilterAllow;
399 }
400 
402  SandeshResponse *resp) {
403  HaStaleDevVnEntry *entry = static_cast<HaStaleDevVnEntry *>(kentry);
404  OvsdbHaStaleDevVnExport dentry;
405  dentry.set_state(entry->StateString());
406  dentry.set_dev_name(entry->dev_name());
407  dentry.set_dev_ip(entry->dev_ip().to_string());
408  dentry.set_vn_uuid(UuidToString(entry->vn_uuid()));
409  dentry.set_vn_name(entry->vn_name());
410  dentry.set_vxlan_id(entry->vxlan_id());
412  UuidToString(entry->vn_uuid()), "");
413  dentry.set_l2_route_table(task.EncodeFirstPage());
414 
415  OvsdbHaStaleDevVnExportResp *d_resp =
416  static_cast<OvsdbHaStaleDevVnExportResp *>(resp);
417  std::vector<OvsdbHaStaleDevVnExport> &dev_vn =
418  const_cast<std::vector<OvsdbHaStaleDevVnExport>&>(
419  d_resp->get_dev_vn());
420  dev_vn.push_back(dentry);
421 }
422 
424  return static_cast<SandeshResponse *>(new OvsdbHaStaleDevVnExportResp());
425 }
426 
428  ConnectionStateTable *con_table =
430  ConnectionStateEntry *con_entry = con_table->Find(dev_name_);
431  if (con_entry == NULL) {
432  return NULL;
433  }
434  return static_cast<KSyncObject *>(con_entry->ha_stale_dev_vn_table());
435 }
436 
437 void OvsdbHaStaleDevVnExportReq::HandleRequest() const {
439  new HaStaleDevVnSandeshTask(context(), get_dev_name(),
440  get_vn_uuid());
442  scheduler->Enqueue(task);
443 }
444 
boost::function< void(void)> StaleClearL2EntryCb
int ha_stale_route_interval() const
Definition: ovsdb_client.cc:62
void UpdateResp(KSyncEntry *kentry, SandeshResponse *resp)
const std::string & device_display_name() const
OVSDB::OvsdbClient * ovsdb_client() const
Definition: agent.h:1126
DBFilterResp OvsdbDBEntryFilter(const DBEntry *entry, const OvsdbDBEntry *ovsdb_entry)
void Change(KSyncEntry *entry)
OvsdbDBObject * table()
Definition: ovsdb_entry.h:96
OvsPeer * route_peer() const
static Agent * GetInstance()
Definition: agent.h:436
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
Definition: vrf.h:86
const std::string & vn_name() const
Definition: ha_stale_vn.cc:69
HaStaleL2RouteTable * old_l2_table_
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
bool IsResolved()
const IpAddress & tor_ip() const
virtual void EmptyTable(void)
std::string StateString() const
boost::uuids::uuid vn_uuid_
const boost::uuids::uuid & vn_uuid() const
boost::asio::ip::address IpAddress
Definition: address.h:13
OvsPeer * Allocate(const IpAddress &peer_ip)
void StaleClearAddEntry(uint64_t time_stamp, HaStaleL2RouteEntry *entry, StaleClearL2EntryCb cb)
virtual void OvsdbRegisterDBTable(DBTable *tbl)
Definition: ovsdb_object.cc:76
boost::uuids::uuid uuid
std::unique_ptr< OvsPeer > route_peer_
static std::string UuidToString(const boost::uuids::uuid &id)
Definition: string_util.h:138
int vxlan_id() const
static void Unregister(KSyncObject *)
bool delete_scheduled()
Definition: ksync_object.h:146
std::string EncodeFirstPage()
int GetTaskId(const std::string &name)
Definition: task.cc:856
HaStaleDevVnEntry(OvsdbDBObject *table, const boost::uuids::uuid &vn_uuid)
ConnectionStateEntry * state() const
FilterResp Filter(KSyncEntry *entry)
HaStaleDevVnTable * ha_stale_dev_vn_table() const
TaskScheduler * task_scheduler() const
Definition: agent.h:1120
AgentRouteTable * bridge_table() const
Definition: ha_stale_vn.cc:73
bool Get(const std::string &key, std::string *val) const
OvsPeer * route_peer() const
KSyncObject * GetObject(OvsdbClientSession *session)
Definition: agent.h:358
void SafeNotifyEvent(KSyncEntry *entry, KSyncEntry::KSyncEvent event)
static TaskScheduler * GetInstance()
Definition: task.cc:547
void Enqueue(Task *task)
Enqueues a task for running. Starts task if all policy rules are met else puts task in waitq...
Definition: task.cc:636
ConnectionStateEntryPtr state_
DBTableBase * GetDBTable()
Definition: ksync_object.h:244
ConnectionStateEntry * state() const
void Free(OvsPeer *peer)
PhysicalDeviceVnTable * physical_device_vn_table() const
Definition: agent.h:635
KSyncObject * GetObject() const
Definition: ovsdb_entry.cc:194
AgentRouteTable * GetBridgeRouteTable() const
Definition: vrf.cc:334
void TriggerAck(HaStaleL2RouteTable *table)
void VnReEvalEnqueue(const boost::uuids::uuid &vn_uuid)
KSyncEntry * Find(const KSyncEntry *key)
Definition: ksync_object.cc:99
AgentRouteTable * oper_bridge_table_
bool IsLess(const KSyncEntry &) const
bool Add(const std::string &key, const std::string &val)
KSyncEntry * GetReference(const KSyncEntry *key)
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
ConnectionStateEntry * Find(const std::string &device_name)
bool Cancel()
Definition: timer.cc:150
bool VnReEval(const boost::uuids::uuid &vn_uuid)
WorkQueue< boost::uuids::uuid > * vn_reeval_queue_
bool IsDeleted()
Definition: ksync_entry.h:163
static const uint32_t kStaleTimerJobInterval
uint32_t vxlan_id() const
const std::string & dev_name() const
VrfEntry * GetVrf() const
Definition: vn.h:170
HaStaleDevVnSandeshTask(std::string resp_ctx, AgentSandeshArguments &args)
ConnectionStateTable * connection_table()
Definition: ovsdb_client.cc:40
KSyncEntry * DBToKSyncEntry(const DBEntry *)
void StaleClearDelEntry(uint64_t time_stamp, HaStaleL2RouteEntry *entry)
static const uint32_t kNumEntriesPerIteration
void EncodeArgs(AgentSandeshArguments &args)
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
OvsPeerManager * manager_
KSyncEntry * UnresolvedReference()
const boost::uuids::uuid & GetUuid() const
Definition: vn.h:161
const string & GetName() const
Definition: vn.h:162
HaStaleL2RouteTable * l2_table_
const std::string & dev_name() const
IpAddress dev_ip() const
const std::string & vn_name() const
KSyncEntry * Alloc(const KSyncEntry *key, uint32_t index)
OvsdbDBObject * table_
Definition: ovsdb_entry.h:110
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
friend class HaStaleDevVnEntry
VnEntry * vn() const
HaStaleDevVnTable(Agent *agent, OvsPeerManager *manager, ConnectionStateEntry *state, std::string &dev_name)
void set_name(const std::string &name)
Definition: queue_task.h:307
HaStaleVnTable * vn_table_
struct task_ task
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222
void UpdateParams(HaStaleDevVnEntry *dev_vn)