Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <mutex>
7 :
8 : #include <pkt/flow_proto.h>
9 : #include <pkt/pkt_types.h>
10 : #include <pkt/flow_entry.h>
11 : #include <init/agent_param.h>
12 : #include "ksync_flow_index_manager.h"
13 : #include "flowtable_ksync.h"
14 : #include "ksync_init.h"
15 :
16 : #define INDEX_LOCK(idx) \
17 : auto lock = (idx != FlowEntry::kInvalidFlowHandle) \
18 : ? std::unique_lock<std::mutex>(index_list_[idx].mutex_) \
19 : : std::unique_lock<std::mutex>();
20 :
21 : //////////////////////////////////////////////////////////////////////////////
22 : // KSyncFlowIndexManager routines
23 : //////////////////////////////////////////////////////////////////////////////
24 2 : KSyncFlowIndexManager::KSyncFlowIndexManager(KSync *ksync) :
25 2 : ksync_(ksync), proto_(NULL), count_(0), index_list_(), sm_log_count_(0) {
26 2 : }
27 :
28 4 : KSyncFlowIndexManager::~KSyncFlowIndexManager() {
29 2 : if (count_ > 0)
30 262146 : delete [] index_list_;
31 4 : }
32 :
33 2 : void KSyncFlowIndexManager::InitDone(uint32_t count) {
34 2 : proto_ = ksync_->agent()->pkt()->get_flow_proto();
35 2 : count_ = count;
36 262146 : index_list_ = new struct IndexEntry[count_];
37 2 : sm_log_count_ = ksync_->agent()->params()->flow_index_sm_log_count();
38 2 : }
39 :
40 : //////////////////////////////////////////////////////////////////////////////
41 : // KSyncFlowIndexManager Utility methods
42 : //////////////////////////////////////////////////////////////////////////////
43 75 : FlowEntryPtr KSyncFlowIndexManager::FindByIndex(uint32_t idx) {
44 75 : if (index_list_[idx].owner_.get() != NULL)
45 36 : return index_list_[idx].owner_;
46 39 : return FlowEntryPtr(NULL);
47 : }
48 :
49 : //////////////////////////////////////////////////////////////////////////////
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
56 : //////////////////////////////////////////////////////////////////////////////
57 307 : void KSyncFlowIndexManager::Update(FlowEntry *flow) {
58 307 : FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
59 : // flow should not be delete marked
60 307 : assert(!flow->deleted());
61 307 : if (flow->ksync_entry_ == NULL) {
62 144 : CreateInternal(flow);
63 : } else {
64 163 : 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 4 : Delete(flow);
68 4 : CreateInternal(flow);
69 : } else {
70 159 : INDEX_LOCK(flow->flow_handle());
71 159 : uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
72 159 : flow->gen_id(),
73 : flow);
74 159 : flow->ksync_entry_->set_gen_id(flow->gen_id());
75 159 : flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
76 159 : flow->LogFlow(FlowEventLog::FLOW_UPDATE, flow->ksync_entry_,
77 159 : flow->flow_handle(), flow->gen_id());
78 159 : object->Change(flow->ksync_entry_);
79 159 : }
80 : }
81 307 : }
82 :
83 : //////////////////////////////////////////////////////////////////////////////
84 : // Delete:
85 : // Flow module triggers this API to propagate Delete to vrouter
86 : //
87 : // API tries triggers Delete and Release index ownership
88 : //////////////////////////////////////////////////////////////////////////////
89 148 : void KSyncFlowIndexManager::Delete(FlowEntry *flow) {
90 148 : if (flow->ksync_entry_ != NULL) {
91 148 : FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
92 148 : INDEX_LOCK(flow->ksync_entry_->hash_id());
93 148 : ReleaseIndexUnLocked(flow);
94 148 : flow->LogFlow(FlowEventLog::FLOW_DELETE, flow->ksync_entry_,
95 148 : flow->flow_handle(), flow->gen_id());
96 148 : 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 148 : flow->ksync_entry_ = NULL;
101 148 : object->Delete(kentry);
102 148 : }
103 148 : }
104 :
105 : //////////////////////////////////////////////////////////////////////////////
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
110 : //////////////////////////////////////////////////////////////////////////////
111 32 : void KSyncFlowIndexManager::DisableSend(FlowEntry *flow,
112 : uint8_t evict_gen_id) {
113 32 : FlowTableKSyncEntry *kentry = flow->ksync_entry_;
114 32 : if (kentry != NULL) {
115 32 : INDEX_LOCK(flow->flow_handle());
116 32 : kentry->set_evict_gen_id(evict_gen_id);
117 32 : }
118 32 : }
119 :
120 : //////////////////////////////////////////////////////////////////////////////
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
129 : //////////////////////////////////////////////////////////////////////////////
130 230 : void KSyncFlowIndexManager::UpdateFlowHandle(FlowTableKSyncEntry *kentry,
131 : uint32_t index,
132 : uint8_t gen_id) {
133 230 : 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 383 : if (kentry->vrouter_hash_id() == index &&
140 153 : kentry->vrouter_gen_id() == gen_id) {
141 153 : return;
142 : }
143 :
144 77 : FlowEntry *flow = kentry->flow_entry().get();
145 77 : FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
146 : uint8_t evict_gen_id;
147 77 : if (!kentry->IsDeleted() && flow->ksync_entry_!=NULL) {
148 : // if kentry is not deleted flow should always point to this
149 : // ksync entry only
150 77 : assert(kentry == flow->ksync_entry_);
151 77 : FlowEntry *rflow = flow->reverse_flow_entry();
152 :
153 : // Index allocation should happen only if flow_handle is
154 : // kInvalidFlowHandle
155 77 : assert(flow->flow_handle() == FlowEntry::kInvalidFlowHandle);
156 77 : INDEX_LOCK(index);
157 77 : flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
158 77 : flow->set_flow_handle(index, gen_id);
159 77 : object->UpdateFlowHandle(kentry, index);
160 77 : evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
161 77 : flow->gen_id(), flow);
162 77 : kentry->set_gen_id(gen_id);
163 77 : kentry->set_evict_gen_id(evict_gen_id);
164 77 : if (rflow) {
165 : // forward and reverse flow handle should not be same
166 : //assert process to avoid deadlock if both are same
167 77 : assert(flow->flow_handle() != rflow->flow_handle());
168 77 : rflow->flow_table()->UpdateKSync(rflow, true);
169 : }
170 77 : } 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 0 : INDEX_LOCK(index);
178 0 : flow->LogFlow(FlowEventLog::FLOW_HANDLE_ASSIGN, kentry, index, gen_id);
179 0 : 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 0 : if (evict_gen_id == gen_id) {
186 0 : object->UpdateFlowHandle(kentry, index);
187 0 : kentry->set_gen_id(gen_id);
188 0 : kentry->set_evict_gen_id(evict_gen_id);
189 : }
190 0 : }
191 : }
192 :
193 : //////////////////////////////////////////////////////////////////////////////
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
199 : //////////////////////////////////////////////////////////////////////////////
200 378 : void KSyncFlowIndexManager::TriggerKSyncEvent(FlowTableKSyncEntry *kentry,
201 : KSyncEntry::KSyncEvent event) {
202 : FlowTableKSyncObject *object = static_cast<FlowTableKSyncObject *>
203 378 : (kentry->GetObject());
204 378 : INDEX_LOCK(kentry->hash_id());
205 378 : object->GenerateKSyncEvent(kentry, event);
206 378 : }
207 :
208 : //////////////////////////////////////////////////////////////////////////////
209 : // AcquireIndexUnLocked:
210 : // Tries to Acquire flow index by comparing gen id, evicts the entry
211 : // which has an older gen id
212 : //////////////////////////////////////////////////////////////////////////////
213 384 : uint8_t KSyncFlowIndexManager::AcquireIndexUnLocked(uint32_t index,
214 : uint8_t gen_id,
215 : FlowEntry *flow) {
216 384 : uint8_t evict_gen_id = gen_id;
217 384 : if (index == FlowEntry::kInvalidFlowHandle) {
218 77 : return evict_gen_id;
219 : }
220 :
221 307 : if (index_list_[index].owner_ != flow) {
222 148 : if (index_list_[index].owner_ != NULL) {
223 32 : FlowTableKSyncEntry *old = index_list_[index].owner_->ksync_entry_;
224 32 : uint8_t diff = gen_id - old->gen_id();
225 32 : if (diff < kActiveGenIdDiffMax) {
226 : // evict old entry
227 32 : old->set_evict_gen_id(gen_id);
228 32 : old->flow_entry()->LogFlow(FlowEventLog::FLOW_EVICT, old,
229 : index, gen_id);
230 32 : proto_->EvictFlowRequest(old->flow_entry().get(),
231 32 : old->hash_id(), old->gen_id(), gen_id);
232 32 : index_list_[index].owner_ = flow;
233 : } else {
234 : // evict current entry
235 0 : evict_gen_id = old->gen_id();
236 0 : 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
240 0 : flow->LogFlow(FlowEventLog::FLOW_EVICT, flow->ksync_entry_,
241 : flow->flow_handle(), evict_gen_id);
242 0 : proto_->EvictFlowRequest(flow, flow->flow_handle(),
243 0 : flow->gen_id(), evict_gen_id);
244 : }
245 : }
246 : } else {
247 116 : index_list_[index].owner_ = flow;
248 : }
249 : }
250 :
251 307 : return evict_gen_id;
252 : }
253 :
254 : //////////////////////////////////////////////////////////////////////////////
255 : // ReleaseIndexUnLocked:
256 : // Release the held flow index
257 : //////////////////////////////////////////////////////////////////////////////
258 148 : void KSyncFlowIndexManager::ReleaseIndexUnLocked(FlowEntry *flow) {
259 148 : if (flow->ksync_entry_->hash_id() == FlowEntry::kInvalidFlowHandle) {
260 0 : return;
261 : }
262 :
263 148 : if (index_list_[flow->ksync_entry_->hash_id()].owner_ == flow) {
264 116 : index_list_[flow->ksync_entry_->hash_id()].owner_ = NULL;
265 : }
266 : }
267 :
268 148 : void KSyncFlowIndexManager::CreateInternal(FlowEntry *flow) {
269 148 : FlowTableKSyncObject *object = flow->flow_table()->ksync_object();
270 148 : INDEX_LOCK(flow->flow_handle());
271 148 : uint8_t evict_gen_id = AcquireIndexUnLocked(flow->flow_handle(),
272 148 : flow->gen_id(),
273 : flow);
274 148 : FlowTableKSyncEntry key(object, flow, flow->flow_handle());
275 148 : key.set_evict_gen_id(evict_gen_id);
276 148 : flow->ksync_entry_ =
277 148 : 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 148 : flow->ksync_entry_->set_gen_id(flow->gen_id());
282 148 : flow->ksync_entry_->set_evict_gen_id(evict_gen_id);
283 148 : flow->ksync_entry_->set_transaction_id(flow->GetTransactionId());
284 148 : flow->LogFlow(FlowEventLog::FLOW_ADD, flow->ksync_entry_,
285 148 : flow->flow_handle(), flow->gen_id());
286 148 : }
|