OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ksync_flow_index_manager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3  */
4 #include <pkt/flow_proto.h>
5 #include <pkt/pkt_types.h>
6 #include <pkt/flow_entry.h>
7 #include <init/agent_param.h>
9 #include "flowtable_ksync.h"
10 #include "ksync_init.h"
11 
12 #define INDEX_LOCK(idx) \
13  tbb::mutex tmp_mutex, *mutex_ptr;\
14  if (idx == FlowEntry::kInvalidFlowHandle) {\
15  mutex_ptr = &tmp_mutex;\
16  } else {\
17  mutex_ptr = &index_list_[idx].mutex_;\
18  }\
19  tbb::mutex::scoped_lock lock(*mutex_ptr);
20 
22 // KSyncFlowIndexManager routines
25  ksync_(ksync), proto_(NULL), count_(0), index_list_(), sm_log_count_(0) {
26 }
27 
29  if (count_ > 0)
30  delete [] index_list_;
31 }
32 
33 void KSyncFlowIndexManager::InitDone(uint32_t count) {
35  count_ = count;
36  index_list_ = new struct IndexEntry[count_];
38 }
39 
41 // KSyncFlowIndexManager Utility methods
44  if (index_list_[idx].owner_.get() != NULL)
45  return index_list_[idx].owner_;
46  return FlowEntryPtr(NULL);
47 }
48 
50 // Update:
51 // Flow module triggers this API to propagate Add/Change to vrouter
52 //
53 // API tries to acquire flow handle and create the KSync entry for
54 // flow, if there is an existing KSync entry, if validates for change
55 // in flow handle and triggers change / Delete-Add accordingly
58  FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
59  // flow should not be delete marked
60  assert(!flow->deleted());
61  if (flow->ksync_entry_ == NULL) {
62  CreateInternal(flow);
63  } else {
64  if (flow->flow_handle() != flow->ksync_entry_->hash_id()) {
65  // if flow handle changes delete the previous record from
66  // vrouter and install new
67  Delete(flow);
68  CreateInternal(flow);
69  } else {
70  INDEX_LOCK(flow->flow_handle());
71  uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
72  flow->gen_id(),
73  flow);
74  flow->ksync_entry_->set_gen_id(flow->gen_id());
75  flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
77  flow->flow_handle(), flow->gen_id());
78  object->Change(flow->ksync_entry_);
79  }
80  }
81 }
82 
84 // Delete:
85 // Flow module triggers this API to propagate Delete to vrouter
86 //
87 // API tries triggers Delete and Release index ownership
90  if (flow->ksync_entry_ != NULL) {
91  FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
95  flow->flow_handle(), flow->gen_id());
96  FlowTableKSyncEntry *kentry = flow->ksync_entry_;
97  // reset ksync_entry_ before triggering delete as Delete
98  // may just free the entry, if there is nothing to encode
99  // which may inturn free the flow entry pointer
100  flow->ksync_entry_ = NULL;
101  object->Delete(kentry);
102  }
103 }
104 
106 // Delete:
107 // Flow module triggers this API to suppress message to vrouter
108 //
109 // API ensures that evict_gen_id has different value from gen_id
112  uint8_t evict_gen_id) {
113  FlowTableKSyncEntry *kentry = flow->ksync_entry_;
114  if (kentry != NULL) {
115  INDEX_LOCK(flow->flow_handle());
116  kentry->set_evict_gen_id(evict_gen_id);
117  }
118 }
119 
121 // UpdateFlowHandle:
122 // Flow module triggers this API to update flow handle for the reverse
123 // flow.
124 //
125 // API Assigns index and gen id received from vrouter to KSync entry
126 // an let the further operation use correct index and gen-id to
127 // communicate with vrouter
128 // KsyncEntry here should always have kInvalidFlowHandle
131  uint32_t index,
132  uint8_t gen_id) {
133  assert(index != FlowEntry::kInvalidFlowHandle);
134 
135  // Check if index and gen id is corresponding to the info sent
136  // to vrouter, if vrouter has allocated flow index, following
137  // check will fail and it will follow through
138  // to process index allocation
139  if (kentry->vrouter_hash_id() == index &&
140  kentry->vrouter_gen_id() == gen_id) {
141  return;
142  }
143 
144  FlowEntry *flow = kentry->flow_entry().get();
145  FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
146  uint8_t evict_gen_id;
147  if (!kentry->IsDeleted() && flow->ksync_entry_!=NULL) {
148  // if kentry is not deleted flow should always point to this
149  // ksync entry only
150  assert(kentry == flow->ksync_entry_);
151  FlowEntry *rflow = flow->reverse_flow_entry();
152 
153  // Index allocation should happen only if flow_handle is
154  // kInvalidFlowHandle
155  assert(flow->flow_handle() == FlowEntry::kInvalidFlowHandle);
156  INDEX_LOCK(index);
157  flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
158  flow->set_flow_handle(index, gen_id);
159  object->UpdateFlowHandle(kentry, index);
160  evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
161  flow->gen_id(), flow);
162  kentry->set_gen_id(gen_id);
163  kentry->set_evict_gen_id(evict_gen_id);
164  if (rflow) {
165  // forward and reverse flow handle should not be same
166  //assert process to avoid deadlock if both are same
167  assert(flow->flow_handle() != rflow->flow_handle());
168  rflow->flow_table()->UpdateKSync(rflow, true);
169  }
170  } else {
171  // KSync entry is deleted, This happens when Reverse flow
172  // is deleted before getting an ACK from vrouter.
173  // this can happen if we delete the flow itself or if we
174  // get a new index from packet processing which will result
175  // in deletion of this KSync entry
176  // just use the correct key to encode delete msg
177  INDEX_LOCK(index);
178  flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
179  evict_gen_id = AcquireIndexUnLocked(index, gen_id, NULL);
180  // following processing is required only if kentry successfully
181  // acquired the index, on index acquire failure we will anyway
182  // skip sending message to vrouter due to evicted state.
183  // So avoid changing ksync entry handle to avoid replacing
184  // hash id of an active ksync entry (Bug - 1587540)
185  if (evict_gen_id == gen_id) {
186  object->UpdateFlowHandle(kentry, index);
187  kentry->set_gen_id(gen_id);
188  kentry->set_evict_gen_id(evict_gen_id);
189  }
190  }
191 }
192 
194 // TriggerKSyncEvent:
195 // Flow module triggers this API to propagate KSyncEvent to KSync Entry
196 //
197 // API ensures that we hold Index Lock, to allow any pending operation
198 // on KSync Entry to happen with Index Lock Held
201  KSyncEntry::KSyncEvent event) {
202  FlowTableKSyncObject *object = static_cast<FlowTableKSyncObject *>
203  (kentry->GetObject());
204  INDEX_LOCK(kentry->hash_id());
205  object->GenerateKSyncEvent(kentry, event);
206 }
207 
209 // AcquireIndexUnLocked:
210 // Tries to Acquire flow index by comparing gen id, evicts the entry
211 // which has an older gen id
214  uint8_t gen_id,
215  FlowEntry *flow) {
216  uint8_t evict_gen_id = gen_id;
217  if (index == FlowEntry::kInvalidFlowHandle) {
218  return evict_gen_id;
219  }
220 
221  if (index_list_[index].owner_ != flow) {
222  if (index_list_[index].owner_ != NULL) {
223  FlowTableKSyncEntry *old = index_list_[index].owner_->ksync_entry_;
224  uint8_t diff = gen_id - old->gen_id();
225  if (diff < kActiveGenIdDiffMax) {
226  // evict old entry
227  old->set_evict_gen_id(gen_id);
228  old->flow_entry()->LogFlow(FlowEventLog::FLOW_EVICT, old,
229  index, gen_id);
230  proto_->EvictFlowRequest(old->flow_entry().get(),
231  old->hash_id(), old->gen_id(), gen_id);
232  index_list_[index].owner_ = flow;
233  } else {
234  // evict current entry
235  evict_gen_id = old->gen_id();
236  if (flow) {
237  // KSyncEntry can be NULL at this point since acquire
238  // index can be done before creating KSyncEntry
239  // LogFlow needs to handle NULL KSyncEntry pointer
241  flow->flow_handle(), evict_gen_id);
242  proto_->EvictFlowRequest(flow, flow->flow_handle(),
243  flow->gen_id(), evict_gen_id);
244  }
245  }
246  } else {
247  index_list_[index].owner_ = flow;
248  }
249  }
250 
251  return evict_gen_id;
252 }
253 
255 // ReleaseIndexUnLocked:
256 // Release the held flow index
260  return;
261  }
262 
263  if (index_list_[flow->ksync_entry_->hash_id()].owner_ == flow) {
264  index_list_[flow->ksync_entry_->hash_id()].owner_ = NULL;
265  }
266 }
267 
269  FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
270  INDEX_LOCK(flow->flow_handle());
271  uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
272  flow->gen_id(),
273  flow);
274  FlowTableKSyncEntry key(object, flow, flow->flow_handle());
275  key.set_evict_gen_id(evict_gen_id);
276  flow->ksync_entry_ =
277  static_cast<FlowTableKSyncEntry *>(object->Create(&key));
278  // Update gen id after create to handle case where ksync entry
279  // was not constructed newly and was resued, thus gen id was
280  // not updated in create
281  flow->ksync_entry_->set_gen_id(flow->gen_id());
282  flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
285  flow->flow_handle(), flow->gen_id());
286 }
void Delete(FlowEntry *flow)
void LogFlow(FlowEventLog::Event event, FlowTableKSyncEntry *ksync, uint32_t flow_handle, uint8_t gen_id)
Definition: flow_entry.cc:3464
void set_evict_gen_id(uint8_t gen_id)
FlowTable * flow_table() const
Definition: flow_entry.h:597
uint32_t GetTransactionId()
Definition: flow_entry.h:770
Agent * agent() const
Definition: ksync_init.h:39
#define INDEX_LOCK(idx)
uint32_t hash_id() const
FlowEntryPtr FindByIndex(uint32_t idx)
void UpdateKSync(FlowEntry *flow, bool update)
Definition: flow_table.cc:734
struct IndexEntry * index_list_
void CreateInternal(FlowEntry *flow)
FlowTableKSyncEntry * ksync_entry_
Definition: flow_entry.h:839
void EvictFlowRequest(FlowEntry *flow, uint32_t flow_handle, uint8_t gen_id, uint8_t evict_gen_id)
Definition: flow_proto.cc:611
AgentParam * params() const
Definition: agent.h:1218
void InitDone(uint32_t count)
void set_gen_id(uint8_t gen_id)
FlowProto * get_flow_proto() const
Definition: pkt_init.h:43
void Update(FlowEntry *flow)
bool IsDeleted()
Definition: ksync_entry.h:163
uint32_t flow_handle() const
Definition: flow_entry.h:600
void set_transaction_id(uint32_t transaction_id)
uint16_t flow_index_sm_log_count() const
Definition: agent_param.h:258
static const uint32_t kInvalidFlowHandle
Definition: flow_entry.h:521
FlowEntry * reverse_flow_entry()
Definition: flow_entry.h:602
void set_flow_handle(uint32_t flow_handle, uint8_t gen_id)
Definition: flow_entry.cc:1037
uint32_t vrouter_hash_id() const
void UpdateFlowHandle(FlowTableKSyncEntry *kentry, uint32_t index, uint8_t gen_id)
FlowEntryPtr flow_entry() const
void TriggerKSyncEvent(FlowTableKSyncEntry *kentry, KSyncEntry::KSyncEvent event)
bool deleted()
Definition: flow_entry.h:680
uint8_t gen_id() const
Definition: flow_entry.h:599
PktModule * pkt() const
Definition: agent.cc:965
void ReleaseIndexUnLocked(FlowEntry *flow)
FlowTableKSyncObject * ksync_object() const
Definition: flow_table.h:182
static const uint8_t kActiveGenIdDiffMax
void DisableSend(FlowEntry *flow, uint8_t evict_gen_id)
uint8_t AcquireIndexUnLocked(uint32_t index, uint8_t gen_id, FlowEntry *flow)
boost::intrusive_ptr< FlowEntry > FlowEntryPtr
Definition: flow_entry.h:125
KSyncObject * GetObject() const