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