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