OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
unicast_mac_remote_ovsdb.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 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_client_idl.h>
11 #include <ovsdb_client_session.h>
12 #include <logical_switch_ovsdb.h>
14 #include <physical_locator_ovsdb.h>
15 #include <vrf_ovsdb.h>
16 
17 #include <oper/vn.h>
18 #include <oper/vrf.h>
19 #include <oper/nexthop.h>
20 #include <oper/tunnel_nh.h>
21 #include <oper/agent_path.h>
22 #include <oper/bridge_route.h>
23 #include <ovsdb_sandesh.h>
24 #include <ovsdb_types.h>
25 
26 using namespace OVSDB;
27 
29  const std::string mac) : OvsdbDBEntry(table), mac_(mac),
30  logical_switch_name_(table->logical_switch_name()),
31  self_exported_route_(false), sequence_(0), self_sequence_(0),
32  ecmp_suppressed_(false), logical_switch_(NULL, this) {
33 }
34 
36  const BridgeRouteEntry *entry) : OvsdbDBEntry(table),
37  mac_(entry->prefix_address().ToString()),
38  logical_switch_name_(table->logical_switch_name()),
39  self_exported_route_(false), sequence_(0), self_sequence_(0),
40  ecmp_suppressed_(false), logical_switch_(NULL, this) {
41 }
42 
44  const UnicastMacRemoteEntry *entry) : OvsdbDBEntry(table),
45  mac_(entry->mac_), logical_switch_name_(entry->logical_switch_name_),
46  dest_ip_(entry->dest_ip_), self_exported_route_(false), sequence_(0),
47  self_sequence_(0), ecmp_suppressed_(false), logical_switch_(NULL, this) {
48 }
49 
51  struct ovsdb_idl_row *entry) : OvsdbDBEntry(table, entry),
53  logical_switch_name_(table->logical_switch_name()), dest_ip_(),
54  self_exported_route_(false), sequence_(0), self_sequence_(0),
55  ecmp_suppressed_(false), logical_switch_(NULL, this) {
57  if (dest_ip) {
58  dest_ip_ = std::string(dest_ip);
59  }
60 };
61 
63  assert(pl_create_ref_.get() == NULL);
64 }
65 
66 void UnicastMacRemoteEntry::NotifyAdd(struct ovsdb_idl_row *row) {
67  if (ovs_entry() == NULL || ovs_entry() == row) {
68  // this is the first idl row to use let the base infra
69  // use it.
71  return;
72  }
73  dup_list_.insert(row);
74  // trigger change to delete duplicate entries
75  table_->Change(this);
76 }
77 
78 void UnicastMacRemoteEntry::NotifyDelete(struct ovsdb_idl_row *row) {
79  if (ovs_entry() == row) {
81  return;
82  }
83  dup_list_.erase(row);
84 }
85 
87  boost::system::error_code ec;
88  Ip4Address dest_ip = Ip4Address::from_string(dest_ip_, ec);
90  LogicalSwitchEntry key(l_table, logical_switch_name_.c_str());
91  LogicalSwitchEntry *logical_switch =
92  static_cast<LogicalSwitchEntry *>(l_table->GetReference(&key));
93 
95  dest_ip == logical_switch->physical_switch_tunnel_ip()) {
96  // if the route is self exported or if dest tunnel end-point points to
97  // the physical switch itself then donot export this route to OVSDB
98  // release reference to logical switch to trigger delete.
99  logical_switch_ = NULL;
100  return;
101  }
102  logical_switch_ = logical_switch;
103 }
104 
106  logical_switch_ = NULL;
107 }
108 
109 void UnicastMacRemoteEntry::AddMsg(struct ovsdb_idl_txn *txn) {
110  if (!dup_list_.empty()) {
111  // if we have entries in duplicate list clean up all
112  // by encoding a delete message and on ack re-trigger
113  // Add Msg to return to sane state.
114  DeleteMsg(txn);
115  return;
116  }
117 
118  if (logical_switch_.get() == NULL || (dest_ip_.empty() && !stale())) {
119  DeleteMsg(txn);
120  return;
121  }
122 
123  if (!stale()) {
124  // route was self exported but is not the active path
125  if (self_sequence_ != 0 &&
127  // trigger delete of ovs row and add back later
128  // to simulate MAC move.
129  if (ovs_entry_ != NULL) {
130  DeleteMsg(txn);
131  return;
132  }
133  }
134 
135 
136  PhysicalLocatorTable *pl_table =
138  PhysicalLocatorEntry pl_key(pl_table, dest_ip_);
139  /*
140  * we don't take reference to physical locator, just use if locator
141  * is existing or we will create a new one.
142  */
143  PhysicalLocatorEntry *pl_entry =
144  static_cast<PhysicalLocatorEntry *>(pl_table->Find(&pl_key));
145  struct ovsdb_idl_row *pl_row = NULL;
146  if (pl_entry)
147  pl_row = pl_entry->ovs_entry();
148  LogicalSwitchEntry *logical_switch =
149  static_cast<LogicalSwitchEntry *>(logical_switch_.get());
151  logical_switch->ovs_entry(), pl_row, dest_ip_.c_str());
153  }
154 }
155 
156 void UnicastMacRemoteEntry::ChangeMsg(struct ovsdb_idl_txn *txn) {
157  AddMsg(txn);
158 }
159 
160 void UnicastMacRemoteEntry::DeleteMsg(struct ovsdb_idl_txn *txn) {
161  DeleteDupEntries(txn);
162  if (ovs_entry_) {
165  }
166 }
167 
169  if (!IsResolved())
171 }
172 
174  const BridgeRouteEntry *entry =
175  static_cast<const BridgeRouteEntry *>(db_entry);
176  std::string dest_ip;
177 
178  const NextHop *nh = entry->GetActiveNextHop();
179  const TunnelNH *tunnel = NULL;
180  /*
181  * TOR Agent will not have any local VM so only tunnel nexthops
182  * are to be looked into
183  */
184  if (nh && nh->GetType() == NextHop::TUNNEL) {
185  /*
186  * we don't care the about the tunnel type in nh and always program
187  * the entry to ovsdb expecting vrouter to always handle
188  * VxLAN encapsulation.
189  */
190  tunnel = static_cast<const TunnelNH *>(nh);
191  dest_ip = tunnel->GetDip()->to_string();
192  }
193  bool change = false;
194  if (dest_ip_ != dest_ip) {
195  dest_ip_ = dest_ip;
196  change = true;
197  }
198 
199  // Since OVSDB exports routes to evpn table check for self exported route
200  // path in the corresponding evpn route entry, instead of bridge entry
201  VrfEntry *vrf = entry->vrf();
202  EvpnAgentRouteTable *evpn_table =
203  static_cast<EvpnAgentRouteTable *>(vrf->GetEvpnRouteTable());
204  Ip4Address default_ip;
205  EvpnRouteEntry *evpn_rt = evpn_table->FindRoute(entry->prefix_address(), default_ip, 32,
206  entry->GetActiveLabel());
207 
208  bool self_exported_route = false;
209  uint32_t self_sequence = 0;
210  if (evpn_rt != NULL) {
211  const AgentPath *ovs_path =
212  evpn_rt->FindPath((Peer *)table_->client_idl()->route_peer());
213  if (ovs_path != NULL) {
214  const NextHop *ovs_nh = ovs_path->nexthop();
215  assert(ovs_nh != NULL && ovs_nh->GetType() == NextHop::TUNNEL);
216  const TunnelNH *ovs_tunnel = static_cast<const TunnelNH *>(ovs_nh);
217  if (tunnel != NULL &&
218  *(tunnel->GetDip()) == *(ovs_tunnel->GetDip())) {
219  self_exported_route = true;
220  }
221  self_sequence = ovs_path->sequence();
222  }
223  }
224 
225  if (self_exported_route_ != self_exported_route) {
227  change = true;
228  }
229 
230  if (self_sequence_ != self_sequence) {
232  change = true;
233  }
234 
235  const AgentPath *path = entry->GetActivePath();
236  if (path && sequence_ != path->sequence()) {
237  sequence_ = path->sequence();
238  change = true;
239  }
240 
241  if (ecmp_suppressed_ != path->ecmp_suppressed()) {
243  change = true;
244  }
245 
246  return change;
247 }
248 
249 bool UnicastMacRemoteEntry::IsLess(const KSyncEntry &entry) const {
250  const UnicastMacRemoteEntry &ucast =
251  static_cast<const UnicastMacRemoteEntry&>(entry);
252  if (mac_ != ucast.mac_)
253  return mac_ < ucast.mac_;
255 }
256 
258  assert(pl_create_ref_.get() == NULL);
259 
261  LogicalSwitchEntry key(l_table, logical_switch_name_.c_str());
262  LogicalSwitchEntry *l_switch =
263  static_cast<LogicalSwitchEntry *>(l_table->GetReference(&key));
264  if (!l_switch->IsResolved()) {
265  return l_switch;
266  }
267 
268  if (!dest_ip_.empty()) {
269  // check if physical locator is available
270  PhysicalLocatorTable *pl_table =
272  PhysicalLocatorEntry pl_key(pl_table, dest_ip_);
273  PhysicalLocatorEntry *pl_entry =
274  static_cast<PhysicalLocatorEntry *>(pl_table->GetReference(&pl_key));
275  if (!pl_entry->IsResolved()) {
276  if (stale() || !pl_entry->AcquireCreateRequest(this)) {
277  // failed to Acquire Create Request, wait for physical locator
278  // we dont Acquire Create request for stale entry
279  return pl_entry;
280  }
281  pl_create_ref_ = pl_entry;
282  }
283  }
284 
285  return NULL;
286 }
287 
288 const std::string &UnicastMacRemoteEntry::mac() const {
289  return mac_;
290 }
291 
292 const std::string &UnicastMacRemoteEntry::logical_switch_name() const {
293  return logical_switch_name_;
294 }
295 
296 const std::string &UnicastMacRemoteEntry::dest_ip() const {
297  return dest_ip_;
298 }
299 
301  return self_exported_route_;
302 }
303 
305  return sequence_;
306 }
307 
309  return self_sequence_;
310 }
311 
313  return ecmp_suppressed_;
314 }
315 
316 void UnicastMacRemoteEntry::Ack(bool success) {
318  OvsdbDBEntry::Ack(success);
319 }
320 
323 }
324 
326  SandeshUnicastMacRemoteInfo info;
327  switch (event) {
328  case ADD_REQ:
329  info.set_op("Add Requested");
330  break;
331  case DEL_REQ:
332  info.set_op("Delete Requested");
333  break;
334  case ADD_ACK:
335  info.set_op("Add Received");
336  break;
337  case DEL_ACK:
338  info.set_op("Delete Received");
339  break;
340  default:
341  info.set_op("unknown");
342  }
343  info.set_mac(mac_);
344  info.set_logical_switch(logical_switch_name_);
345  info.set_dest_ip(dest_ip_);
346  OVSDB_TRACE(UnicastMacRemote, info);
347 }
348 
349 // Always called from any message encode Add/Change/Delete
350 // to trigger delete for deleted entries.
351 void UnicastMacRemoteEntry::DeleteDupEntries(struct ovsdb_idl_txn *txn) {
352  OvsdbDupIdlList::iterator it = dup_list_.begin();
353  for (; it != dup_list_.end(); it++) {
355  }
356 }
357 
359  // on Ack Release the physical locator create ref, if present
360  if (pl_create_ref_.get() != NULL) {
361  // release creator reference on txn complete
362  PhysicalLocatorEntry *pl_entry =
363  static_cast<PhysicalLocatorEntry *>(pl_create_ref_.get());
364  pl_entry->ReleaseCreateRequest(this);
365  pl_create_ref_ = NULL;
366  }
367 }
368 
370  const std::string &logical_switch_name, VrfOvsdbEntry *vrf) :
371  OvsdbDBObject(idl, true), logical_switch_name_(logical_switch_name),
372  table_delete_ref_(this, NULL), vrf_(vrf) {
373 }
374 
376  // Table unregister will be done by Destructor of KSyncDBObject
377  table_delete_ref_.Reset(NULL);
378 }
379 
382  AgentRouteTable *table = dynamic_cast<AgentRouteTable *>(tbl);
383  table_delete_ref_.Reset(table->deleter());
384 }
385 
386 KSyncEntry *UnicastMacRemoteTable::Alloc(const KSyncEntry *key, uint32_t index) {
387  const UnicastMacRemoteEntry *k_entry =
388  static_cast<const UnicastMacRemoteEntry *>(key);
389  UnicastMacRemoteEntry *entry = new UnicastMacRemoteEntry(this, k_entry);
390  return entry;
391 }
392 
394  const BridgeRouteEntry *entry =
395  static_cast<const BridgeRouteEntry *>(db_entry);
396  UnicastMacRemoteEntry *key = new UnicastMacRemoteEntry(this, entry);
397  return static_cast<KSyncEntry *>(key);
398 }
399 
401  UnicastMacRemoteEntry key(this, row);
402  return static_cast<OvsdbDBEntry *>(CreateStale(&key));
403 }
404 
406  const DBEntry *db_entry, const OvsdbDBEntry *ovsdb_entry) {
407  const BridgeRouteEntry *entry =
408  static_cast<const BridgeRouteEntry *>(db_entry);
409  //Locally programmed multicast route should not be added in
410  //OVS.
411  if (entry->is_multicast()) {
412  return DBFilterIgnore;
413  }
414 
415  if (entry->vrf()->IsDeleted()) {
416  // if notification comes for a entry with deleted vrf,
417  // trigger delete since we donot resue same vrf object
418  // so this entry has to be deleted eventually.
419  return DBFilterDelete;
420  }
421 
422  return DBFilterAccept;
423 }
424 
426  // We do rely on follow up notification of VRF Delete
427  // to handle delete of this route table
428 }
429 
432  // unregister the object if emptytable is called with
433  // object being scheduled for delete
434  if (delete_scheduled()) {
435  // trigger Ack for Vrf entry and reset to NULL
436  vrf_->TriggerAck(this);
437  vrf_ = NULL;
439  }
440 }
441 
442 const std::string &UnicastMacRemoteTable::logical_switch_name() const {
443  return logical_switch_name_;
444 }
445 
447 // Sandesh routines
450  std::string resp_ctx, AgentSandeshArguments &args) :
451  OvsdbSandeshTask(resp_ctx, args) {
452  if (args.Get("ls_name", &ls_name_) == false) {
453  ls_name_ = "";
454  }
455  if (args.Get("mac", &mac_) == false) {
456  mac_ = "";
457  }
458 }
459 
461  std::string resp_ctx, const std::string &ip, uint32_t port,
462  const std::string &ls, const std::string &mac) :
463  OvsdbSandeshTask(resp_ctx, ip, port), ls_name_(ls), mac_(mac) {
464 }
465 
467 }
468 
470  args.Add("ls_name", ls_name_);
471  if (!mac_.empty()) {
472  args.Add("mac", mac_);
473  }
474 }
475 
478  if (!mac_.empty()) {
479  UnicastMacRemoteEntry *entry =
480  static_cast<UnicastMacRemoteEntry *>(kentry);
481  if (entry->mac().find(mac_) != std::string::npos) {
482  return FilterAllow;
483  }
484  return FilterDeny;
485  }
486  return FilterAllow;
487 }
488 
490  SandeshResponse *resp) {
491  UnicastMacRemoteEntry *entry = static_cast<UnicastMacRemoteEntry *>(kentry);
492  OvsdbUnicastMacRemoteEntry oentry;
493  oentry.set_state(entry->StateString());
494  oentry.set_mac(entry->mac());
495  oentry.set_logical_switch(entry->logical_switch_name());
496  oentry.set_dest_ip(entry->dest_ip());
497  oentry.set_self_exported(entry->self_exported_route());
498  oentry.set_sequence(entry->sequence());
499  oentry.set_self_sequence(entry->self_sequence());
500  oentry.set_ecmp_suppressed(entry->ecmp_suppressed());
501  OvsdbUnicastMacRemoteResp *u_resp =
502  static_cast<OvsdbUnicastMacRemoteResp *>(resp);
503  std::vector<OvsdbUnicastMacRemoteEntry> &macs =
504  const_cast<std::vector<OvsdbUnicastMacRemoteEntry>&>(
505  u_resp->get_macs());
506  macs.push_back(oentry);
507 }
508 
510  return static_cast<SandeshResponse *>(new OvsdbUnicastMacRemoteResp());
511 }
512 
514  OvsdbClientSession *session) {
515  VrfOvsdbObject *vrf_obj = session->client_idl()->vrf_ovsdb();
516  VrfOvsdbEntry vrf_key(vrf_obj, ls_name_);
517  VrfOvsdbEntry *vrf_entry =
518  static_cast<VrfOvsdbEntry *>(vrf_obj->Find(&vrf_key));
519  return static_cast<KSyncObject *>(
520  (vrf_entry != NULL) ? vrf_entry->route_table() : NULL);
521 }
522 
523 void OvsdbUnicastMacRemoteReq::HandleRequest() const {
525  new UnicastMacRemoteSandeshTask(context(), get_session_remote_ip(),
526  get_session_remote_port(),
527  get_logical_switch(), get_mac());
529  scheduler->Enqueue(task);
530 }
531 
KSyncObject * GetObject(OvsdbClientSession *session)
EvpnRouteEntry * FindRoute(const MacAddress &mac, const IpAddress &ip_addr, uint32_t plen, uint32_t ethernet_tag)
char * ovsdb_wrapper_ucast_mac_remote_mac(struct ovsdb_idl_row *row)
#define OVSDB_TRACE(obj,...)
void Change(KSyncEntry *entry)
const std::string & logical_switch_name() const
OvsdbClientIdl * client_idl()
Definition: ovsdb_object.h:76
UnicastMacRemoteEntry(UnicastMacRemoteTable *table, const std::string mac)
virtual void NotifyDelete(struct ovsdb_idl_row *)
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
bool IsResolved()
AgentRouteTable * GetEvpnRouteTable() const
Definition: vrf.cc:330
virtual void EmptyTable(void)
Agent supports multiple route tables - Inet-unicast (IPv4/IPv6), Inet-multicast, bridge, EVPN (Type2/Type5). This base class contains common code for all types of route tables.
Definition: agent_route.h:109
void DeleteDupEntries(struct ovsdb_idl_txn *)
void AddMsg(struct ovsdb_idl_txn *)
std::string StateString() const
bool IsDeleted() const
Definition: db_entry.h:49
DBFilterResp OvsdbDBEntryFilter(const DBEntry *entry, const OvsdbDBEntry *ovsdb_entry)
bool is_multicast() const
Definition: agent_route.h:274
char * ovsdb_wrapper_ucast_mac_remote_dst_ip(struct ovsdb_idl_row *row)
KSyncEntry * Alloc(const KSyncEntry *key, uint32_t index)
bool AcquireCreateRequest(KSyncEntry *creator)
OvsdbDBEntry * AllocOvsEntry(struct ovsdb_idl_row *row)
virtual void OvsdbRegisterDBTable(DBTable *tbl)
Definition: ovsdb_object.cc:76
void ovsdb_wrapper_delete_ucast_mac_remote(struct ovsdb_idl_row *row)
const Ip4Address * GetDip() const
Definition: tunnel_nh.h:37
UnicastMacRemoteTable * route_table()
Definition: vrf_ovsdb.h:57
LifetimeActor * deleter()
Definition: agent_route.cc:451
PhysicalLocatorTable * physical_locator_table()
void ChangeMsg(struct ovsdb_idl_txn *)
static void Unregister(KSyncObject *)
bool delete_scheduled()
Definition: ksync_object.h:146
Type GetType() const
Definition: nexthop.h:405
struct ovsdb_idl_row * ovs_entry()
Definition: ovsdb_entry.h:94
static string ToString(PhysicalDevice::ManagementProtocol proto)
const AgentPath * GetActivePath() const
Definition: agent_route.cc:876
NextHop * nexthop() const
Definition: agent_path.cc:87
void TriggerAck(UnicastMacRemoteTable *table)
Definition: vrf_ovsdb.cc:99
virtual void NotifyAdd(struct ovsdb_idl_row *)
void ovsdb_wrapper_add_ucast_mac_remote(struct ovsdb_idl_txn *txn, struct ovsdb_idl_row *row, const char *mac, struct ovsdb_idl_row *ls, struct ovsdb_idl_row *pl, const char *dest_ip)
UnicastMacRemoteTable(OvsdbClientIdl *idl, const std::string &logical_switch_name, VrfOvsdbEntry *vrf)
bool Get(const std::string &key, std::string *val) const
const std::string & logical_switch_name() const
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
void UpdateResp(KSyncEntry *kentry, SandeshResponse *resp)
uint32_t sequence() const
Definition: agent_path.h:328
const NextHop * GetActiveNextHop() const
Definition: agent_route.cc:881
Definition: trace.h:220
bool stale() const
Definition: ksync_entry.h:161
struct ovsdb_idl_row * ovs_entry_
Definition: ovsdb_entry.h:111
UnicastMacRemoteSandeshTask(std::string resp_ctx, AgentSandeshArguments &args)
const std::string & mac() const
KSyncEntry * Find(const KSyncEntry *key)
Definition: ksync_object.cc:99
struct ovsdb_idl_row * ovs_entry()
Definition: ovsdb_entry.h:47
Definition: peer.h:44
bool Add(const std::string &key, const std::string &val)
KSyncEntry * GetReference(const KSyncEntry *key)
virtual const PrefixType & prefix_address() const
Returns the value of a stored prefix address (IPv4, IPv6 or MAC address)
Definition: agent_route.h:375
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
virtual void NotifyDelete(struct ovsdb_idl_row *)
Definition: ovsdb_entry.cc:190
VrfOvsdbObject * vrf_ovsdb()
LogicalSwitchTable * logical_switch_table()
virtual void NotifyAdd(struct ovsdb_idl_row *)
Definition: ovsdb_entry.cc:179
void DeleteMsg(struct ovsdb_idl_txn *)
LifetimeRef< UnicastMacRemoteTable > table_delete_ref_
void EncodeArgs(AgentSandeshArguments &args)
KSyncEntry * CreateStale(const KSyncEntry *key)
bool IsLess(const KSyncEntry &) const
virtual void Ack(bool success)
Definition: ovsdb_entry.cc:198
VrfEntry * vrf() const
Definition: agent_route.h:275
bool ecmp_suppressed() const
Definition: agent_path.h:357
virtual void OvsdbRegisterDBTable(DBTable *tbl)
const std::string & dest_ip() const
void ReleaseCreateRequest(KSyncEntry *creator)
virtual AgentPath * FindPath(const Peer *peer) const
Definition: agent_route.cc:864
OvsdbDBObject * table_
Definition: ovsdb_entry.h:110
KSyncEntry * DBToKSyncEntry(const DBEntry *)
struct task_ task
virtual uint32_t GetActiveLabel() const