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