OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mac_ip_learning.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3  */
4 #include <init/agent_param.h>
5 #include <oper/vn.h>
6 #include <oper/sg.h>
7 #include <oper/vrf.h>
8 #include <oper/nexthop.h>
10 #include <oper/route_common.h>
11 #include "mac_learning_proto.h"
13 #include "mac_learning_init.h"
14 #include "mac_ip_learning.h"
15 #include "mac_learning_mgmt.h"
16 #include "mac_learning_event.h"
17 
18 
20  agent_(agent),
21  work_queue_(this), macip_map_mutex_() {
23  boost::bind(&MacIpLearningTable::MacIpEntryHcNotify, this, _1));
24 }
25 
27  switch(ptr->event()) {
29  agent()->mac_learning_proto()->ProcessProto(ptr->pkt_info());
30  break;
31 
33  Add(ptr->mac_learning_entry());
34  break;
35 
37  Resync(ptr->mac_learning_entry());
38  break;
39 
41  Delete(ptr->mac_learning_entry());
42  break;
44  DetectIpMove(ptr);
45  break;
46 
49  break;
50 
51  default:
52  assert(0);
53  }
54  return true;
55 }
58  if (add == false) {
60  }
63 }
65  MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
66  MacIpLearningKey key(entry->vrf_id(), entry->IpAddr());
67  //check whether IP belongs to subnet of VN
68  const VmInterface *vm_intf =
69  dynamic_cast<const VmInterface *>(entry->intf());
70  if (!vm_intf ||
71  !vm_intf->vn()->GetIpam(entry->IpAddr())) {
72  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
73  entry->IpAddr().to_string(), entry->Mac().ToString(),
74  entry->intf()->name(),
75  "ip address does not belong to same subnet, ignoring");
76  return;
77  }
78  tbb::mutex::scoped_lock lock(macip_map_mutex_);
79  MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
80  if (it != mac_ip_learning_entry_map_.end()) {
81  MacIpLearningEntry *existing_entry =
82  dynamic_cast<MacIpLearningEntry *>(it->second.get());
83  if ( existing_entry && existing_entry->Mac() == entry->Mac()) {
84  // ignore duplicate add requests, it is possible that
85  // duplicate requests may come till route processing is done.
86  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
87  entry->IpAddr().to_string(), entry->Mac().ToString(),
88  entry->intf()->name(),
89  "duplicate add request, ingoring");
90  return;
91  }
92  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
93  entry->IpAddr().to_string(), entry->Mac().ToString(),
94  entry->intf()->name(),
95  "local IP move detected, delete and add with new mac");
96  //Entry already present, clear the entry
97  if (it->second->deleted() == false) {
98  it->second->Delete();
99  EnqueueMgmtReq(it->second, false);
100  }
101  mac_ip_learning_entry_map_[key] = ptr;
102  } else {
103  // check whether mac limit reached for learning new mac-ip
104  // on the interface
105  if (vm_intf->IsMaxMacIpLearnt()) {
106  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
107  entry->IpAddr().to_string(), entry->Mac().ToString(),
108  entry->intf()->name(),
109  "max mac ip learnt limit reached on interface");
110  return;
111  }
112 
114  }
115  ptr->Add();
116  EnqueueMgmtReq(ptr, true);
117 }
118 
120  if (ptr->deleted() == true) {
121  return;
122  }
123  MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
124  if (entry == NULL) {
125  return;
126  }
127 
128  tbb::mutex::scoped_lock lock(macip_map_mutex_);
129  MacIpLearningKey key(ptr->vrf_id(), entry->IpAddr());
131  return;
132  }
133  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
134  entry->IpAddr().to_string(), entry->Mac().ToString(),
135  entry->intf()->name(), "Delete");
136 
137  ptr->Delete();
138  mac_ip_learning_entry_map_.erase(key);
139  EnqueueMgmtReq(ptr, false);
140 }
141 
143  MacIpLearningEntry *entry = dynamic_cast<MacIpLearningEntry *>(ptr.get());
144  if (entry == NULL) {
145  return;
146  }
147  MacIpLearningKey key(ptr->vrf_id(), entry->IpAddr());
148  tbb::mutex::scoped_lock lock(macip_map_mutex_);
150  return;
151  }
152 
153  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, entry->vrf()->GetName(),
154  entry->IpAddr().to_string(), entry->Mac().ToString(),
155  entry->intf()->name(), "Resync");
156  ptr->Resync();
157  EnqueueMgmtReq(ptr, true);
158 }
159 
161  MacIpLearningKey key(ptr->vrf_id(), ptr->ip());
162  tbb::mutex::scoped_lock lock(macip_map_mutex_);
163  MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
164  if (it == mac_ip_learning_entry_map_.end()) {
165  return;
166  }
167  MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
168  if (!mac_ip_entry || mac_ip_entry->Mac() == ptr->mac()) {
169  return;
170  }
171 
172  VrfEntry *vrf = Agent::GetInstance()->vrf_table()->FindVrfFromId(ptr->vrf_id());
173  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, vrf?vrf->GetName():"NULL",
174  ptr->ip().to_string(), mac_ip_entry->Mac().ToString(),
175  mac_ip_entry->intf()->name(),
176  "IP Move detected, deleting local entry");
177 
178  it->second->Delete();
179  EnqueueMgmtReq(it->second, false);
180  mac_ip_learning_entry_map_.erase(key);
181 }
183  MacAddress &mac) {
186  vrf_id, ip, mac));
187  Enqueue(ptr);
188 }
190  const HealthCheckInstanceService *instance_service) {
191  const HealthCheckMacIpInstanceService *mac_ip_instance_service =
192  dynamic_cast<const HealthCheckMacIpInstanceService *>(instance_service);
193  if (mac_ip_instance_service) {
194  IpAddress ip = mac_ip_instance_service->destination_ip();
195  MacAddress mac = mac_ip_instance_service->destination_mac();
196  uint32_t vrf_id =
197  mac_ip_instance_service->interface()->vrf()->vrf_id();
200  vrf_id, ip, mac));
201  Enqueue(ptr);
202  }
203 }
205  MacIpLearningKey key(ptr->vrf_id(), ptr->ip());
206  tbb::mutex::scoped_lock lock(macip_map_mutex_);
207  MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
208  if (it == mac_ip_learning_entry_map_.end()) {
209  return;
210  }
211  MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
212  if (mac_ip_entry->Mac() == ptr->mac()) {
213  MAC_IP_LEARNING_TRACE(MacLearningTraceBuf, mac_ip_entry->vrf()->GetName(),
214  mac_ip_entry->IpAddr().to_string(), mac_ip_entry->Mac().ToString(),
215  mac_ip_entry->intf()->name(), "MACIP unreachable, trigger delete");
216  it->second->Delete();
217  EnqueueMgmtReq(it->second, false);
218  mac_ip_learning_entry_map_.erase(key);
219  }
220 }
221 
223  work_queue_.Enqueue(req);
224  return;
225 }
228  tbb::mutex::scoped_lock lock(macip_map_mutex_);
229  MacIpLearningEntryMap::iterator it = mac_ip_learning_entry_map_.find(key);
230  if (it == mac_ip_learning_entry_map_.end()) {
231  return NULL;
232  }
233 
234  MacIpLearningEntry *mac_ip_entry = dynamic_cast<MacIpLearningEntry *>( it->second.get());
235  return mac_ip_entry;
236 }
238  MacIpLearningKey key(vrf_id, ip);
239  MacIpLearningEntry *entry = Find(key);
240  if (entry) {
241  return entry->Mac();
242  }
243  return MacAddress();
244 
245 }
246 
248  uint32_t vrf_id, const IpAddress &ip,
249  const MacAddress &mac, InterfaceConstRef intf) :
250  MacLearningEntry(vrf_id), mac_ip_learning_table_(table),
251  key_(vrf_id, ip), ip_(ip), mac_(mac),
252  intf_(intf), vn_(NULL), hc_service_(NULL), hc_instance_(NULL) {
253  const VmInterface *vm_port = dynamic_cast<const VmInterface *>(intf_.get());
254  assert(vm_port);
255  vn_ = vm_port->vn();
256 
257 }
260  data->is_add = true;
261  data->mac_ip_list_.list_.insert(
263  DBRequest req;
265  req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, intf_->GetUuid(), ""));
266  req.data.reset(data);
269  return 0;
270 }
271 
273  if (hc_instance_ && hc_service_) {
275  hc_instance_ = NULL;
276  hc_service_ = NULL;
277  }
279  data->is_add = false;
280  data->mac_ip_list_.list_.insert(
282  DBRequest req;
284  req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, intf_->GetUuid(), ""));
285  req.data.reset(data);
287 }
288 
291 }
292 
295 }
296 
298  HealthCheckService *hc_service =
299  GetHealthCheckService(vn_.get());
300  if (hc_service_ != hc_service) {
301  if (hc_service_ == NULL) {
302  AddHealthCheckService(hc_service);
303  } else {
304  if (hc_instance_) {
306  }
307  hc_instance_ = NULL;
308  hc_service_= NULL;
309  if (hc_service) {
310  AddHealthCheckService(hc_service);
311  }
312  }
313  } else if (hc_service_) {
315  }
316 }
318  if (service) {
319  hc_service_ = service;
320  IpAddress gateway_ip = vn_->GetGatewayFromIpam(ip_);
321  const VmInterface *vm_intf = static_cast< const VmInterface *>(intf_.get());
322  //TODO: add validation check for null gateway ip
324  const_cast< VmInterface *>(vm_intf), NULL,
325  gateway_ip, ip_, mac_, false, false);
327  }
328 }
329 
331  //1. check if hc is attached
332  const boost::uuids::uuid hc_uuid = vn->health_check_uuid();
333  if (hc_uuid == boost::uuids::nil_uuid()) {
334  return NULL;
335  }
336  HealthCheckService *hc_service = Agent::GetInstance()->
337  health_check_table()->Find(hc_uuid);
338  //2. if attached , check whether target ip present in tragte ip list
339  if (!hc_service) {
340  return NULL;
341  }
342  if (hc_service->IsTargetIpPresent(IpAddr())) {
343  return hc_service;
344  }
345 
346  return NULL;
347 }
349  table_(table),
350  queue_(table_->agent()->task_scheduler()->GetTaskId(kTaskMacLearning),
351  0,
352  boost::bind(&MacIpLearningRequestQueue::HandleEvent,this,_1)) {
353 }
354 
356  return table_->RequestHandler(ptr);
357 }
void Enqueue(MacLearningMgmtRequestPtr &ptr)
bool RequestHandler(MacLearningEntryRequestPtr ptr)
MacIpLearningEntry * Find(const MacIpLearningKey &key)
InterfaceRef interface() const
Definition: health_check.h:147
VnEntryConstRef vn_
void Delete(MacLearningEntryPtr ptr)
bool IsTargetIpPresent(IpAddress &ip)
Definition: health_check.h:350
InterfaceConstRef intf_
static Agent * GetInstance()
Definition: agent.h:436
Definition: vrf.h:86
void RegisterHealthCheckNotifyCallback(HealthCheckNotifyCallback fn)
Definition: health_check.h:449
void MacIpEntryUnreachable(MacLearningEntryRequestPtr ptr)
boost::shared_ptr< MacLearningMgmtRequest > MacLearningMgmtRequestPtr
IpAddress destination_ip() const
HealthCheckService * GetHealthCheckService(const VnEntry *vn)
MacIpLearningEntryMap mac_ip_learning_entry_map_
HealthCheckService * hc_service_
boost::asio::ip::address IpAddress
Definition: address.h:13
MacLearningProto * mac_learning_proto() const
Definition: agent.h:1005
void Enqueue(MacLearningEntryRequestPtr req)
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
MacIpLearningTable * table_
const Interface * intf()
InterfaceTable * interface_table() const
Definition: agent.h:465
bool Enqueue(DBRequest *req)
Definition: db_table.cc:194
MacLearningModule * mac_learning_module() const
Definition: agent.h:1013
boost::uuids::uuid uuid
MacAddress GetPairedMacAddress(uint32_t vrf_id, const IpAddress &ip)
const string & GetName() const
Definition: vrf.h:100
void set_service(HealthCheckService *service)
Definition: health_check.cc:82
void AddHealthCheckService(HealthCheckService *service)
MacAddress & Mac()
void Add(MacLearningEntryPtr ptr)
VmInterface::LearntMacIpList mac_ip_list_
std::string ToString() const
Definition: mac_address.cc:53
void StopHealthCheckService(HealthCheckInstanceBase *instance)
VrfEntry * FindVrfFromId(size_t index)
Definition: vrf.cc:884
tbb::mutex macip_map_mutex_
Definition: agent.h:358
MacIpLearningRequestQueue work_queue_
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
MacIpLearningEntry(MacIpLearningTable *table, uint32_t vrf_id_, const IpAddress &ip, const MacAddress &mac, InterfaceConstRef intf)
SandeshTraceBufferPtr MacLearningTraceBuf
DBOperation oper
Definition: db_table.h:42
boost::intrusive_ptr< const Interface > InterfaceConstRef
Definition: agent.h:51
boost::shared_ptr< MacLearningEntryRequest > MacLearningEntryRequestPtr
const VnEntry * vn() const
MacIpLearningTable(Agent *agent, MacLearningProto *proto)
virtual bool UpdateInstanceTask()
Definition: health_check.h:130
void DetectIpMove(MacLearningEntryRequestPtr ptr)
void Enqueue(MacLearningEntryRequestPtr ptr)
HealthCheckInstanceBase * StartHealthCheckService(VmInterface *intrface, VmInterface *paired_vmi, const IpAddress &source_ip, const IpAddress &destination_ip, const MacAddress &destination_mac, bool ignore_status_event, bool multi_hop)
Definition: vn.h:151
VrfTable * vrf_table() const
Definition: agent.h:485
void Delete()
Definition: db_entry.cc:131
HealthCheckTable * health_check_table() const
Definition: agent.cc:933
IpAddress & IpAddr()
bool HandleEvent(MacLearningEntryRequestPtr ptr)
const boost::uuids::uuid & health_check_uuid() const
Definition: vn.h:242
const std::string & name() const
Definition: interface.h:114
void EnqueueMgmtReq(MacLearningEntryPtr ptr, bool add)
void MacIpEntryHcNotify(const HealthCheckInstanceService *instance_service)
virtual const MacAddress destination_mac() const
Definition: health_check.h:261
HealthCheckInstanceBase * hc_instance_
void EnqueueToTable(MacLearningEntryRequestPtr req)
VrfEntry * vrf() const
std::pair< MacIpLearningKey, MacLearningEntryPtr > MacIpLearningEntryPair
bool ProcessProto(boost::shared_ptr< PktInfo > msg_info)
MacIpLearningRequestQueue(MacIpLearningTable *table)
void Resync(MacLearningEntryPtr ptr)
MacLearningMgmtManager * mac_learning_mgmt() const
#define kTaskMacLearning
Definition: agent.h:341
MacIpLearningTable * mac_ip_learning_table_
boost::shared_ptr< MacLearningEntry > MacLearningEntryPtr