OpenSDN source code
flow_table.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <vector>
6 #include <bitset>
7 #include <mutex>
8 
9 #include <boost/date_time/posix_time/posix_time.hpp>
10 #include <boost/assign/list_of.hpp>
11 #include <boost/unordered_map.hpp>
12 #include <sandesh/sandesh_trace.h>
13 #include <base/address_util.h>
14 #include <pkt/flow_table.h>
17 
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
20 #include <base/os.h>
21 
22 #include <route/route.h>
23 #include <cmn/agent_cmn.h>
24 #include <oper/interface_common.h>
25 #include <oper/nexthop.h>
26 
27 #include <init/agent_param.h>
28 #include <cmn/agent_cmn.h>
29 #include <cmn/agent_stats.h>
30 #include <oper/route_common.h>
31 #include <oper/vrf.h>
32 #include <oper/vm.h>
33 #include <oper/sg.h>
34 #include <oper/tunnel_nh.h>
35 
36 #include <filter/packet_header.h>
37 #include <filter/acl.h>
38 
39 #include <pkt/proto.h>
40 #include <pkt/proto_handler.h>
41 #include <pkt/pkt_handler.h>
42 #include <pkt/flow_proto.h>
43 #include <pkt/pkt_types.h>
44 #include <pkt/pkt_sandesh_flow.h>
45 #include <pkt/flow_mgmt.h>
46 #include <pkt/flow_event.h>
47 
48 const uint32_t FlowEntryFreeList::kInitCount;
50 const uint32_t FlowEntryFreeList::kGrowSize;
53 
55 
57 // FlowTable constructor/destructor
59 FlowTable::FlowTable(Agent *agent, uint16_t table_index) :
60  agent_(agent),
61  rand_gen_(boost::uuids::random_generator()),
62  table_index_(table_index),
63  ksync_object_(NULL),
64  flow_entry_map_(),
65  free_list_(this),
66  flow_task_id_(0),
67  flow_update_task_id_(0),
68  flow_delete_task_id_(0),
69  flow_ksync_task_id_(0),
70  flow_logging_task_id_(0) {
71 }
72 
74  assert(flow_entry_map_.size() == 0);
75 }
76 
84  return;
85 }
86 
88 }
89 
91 }
92 
93 // Concurrency check to ensure all flow-table and free-list manipulations
94 // are done from FlowEvent task context only
95 //exception: freelist free function can be accessed by flow logging task
96 bool FlowTable::ConcurrencyCheck(int task_id, bool check_task_instance) {
97  Task *current = Task::Running();
98  // test code invokes FlowTable API from main thread. The running task
99  // will be NULL in such cases
100  if (current == NULL) {
101  return true;
102  }
103 
104  if (current->task_code_id() != task_id)
105  return false;
106  if (check_task_instance) {
107  if (current->task_data_id() != table_index_)
108  return false;
109  }
110  return true;
111 }
112 
113 bool FlowTable::ConcurrencyCheck(int task_id) {
114  return ConcurrencyCheck(task_id, true);
115 }
116 
118 // FlowTable Add/Delete routines
120 
122  assert(ConcurrencyCheck(flow_task_id_) == true);
123  FlowEntryMap::iterator it;
124 
125  it = flow_entry_map_.find(key);
126  if (it != flow_entry_map_.end()) {
127  return it->second;
128  } else {
129  return NULL;
130  }
131 }
132 
133 void FlowTable::Copy(FlowEntry *lhs, FlowEntry *rhs, bool update) {
134  /* Flow copy, if results in UUID change, stop updating UVE stats
135  * for old flow
136  */
137  if (update==false)
138  DeleteFlowUveInfo(lhs);
139 
140  RevFlowDepParams params;
141  lhs->RevFlowDepInfo(&params);
142  DeleteFlowInfo(lhs, params);
143  if (rhs)
144  lhs->Copy(rhs, update);
145 }
146 
147 FlowEntry *FlowTable::Locate(FlowEntry *flow, uint64_t time) {
148  assert(ConcurrencyCheck(flow_task_id_) == true);
149  std::pair<FlowEntryMap::iterator, bool> ret;
150  ret = flow_entry_map_.insert(FlowEntryMapPair(flow->key(), flow));
151  if (ret.second == true) {
153  ret.first->second->set_on_tree();
154  return flow;
155  }
156 
157  return ret.first->second;
158 }
159 
160 void FlowTable::Add(FlowEntry *flow, FlowEntry *rflow) {
161  uint64_t time = UTCTimestampUsec();
162  FlowEntry *new_flow = Locate(flow, time);
163  FlowEntry *new_rflow = (rflow != NULL) ? Locate(rflow, time) : NULL;
164 
165  FLOW_LOCK(new_flow, new_rflow, FlowEvent::FLOW_MESSAGE);
166  AddInternal(flow, new_flow, rflow, new_rflow, false, false);
167 }
168 
169 void FlowTable::Update(FlowEntry *flow, FlowEntry *rflow) {
170  bool fwd_flow_update = true;
171  FlowEntry *new_flow = Find(flow->key());
172 
173  FlowEntry *new_rflow = (rflow != NULL) ? Find(rflow->key()) : NULL;
174  bool rev_flow_update = true;
175  if (rflow && new_rflow == NULL) {
176  uint64_t time = UTCTimestampUsec();
177  new_rflow = Locate(rflow, time);
178  rev_flow_update = false;
179  }
180 
181  FLOW_LOCK(new_flow, new_rflow, FlowEvent::FLOW_MESSAGE);
182  AddInternal(flow, new_flow, rflow, new_rflow, fwd_flow_update,
183  rev_flow_update);
184 }
185 
187  FlowEntry *rflow_req, FlowEntry *rflow,
188  bool fwd_flow_update, bool rev_flow_update) {
189  // Set trace flags for a flow
190  bool trace = agent_->pkt()->get_flow_proto()->ShouldTrace(flow, rflow);
191  if (flow)
192  flow->set_trace(trace);
193  if (rflow)
194  rflow->set_trace(trace);
195 
196  // The forward and reverse flow in request are linked. Unlink the flows
197  // first. Flow table processing will link them if necessary
198  flow_req->set_reverse_flow_entry(NULL);
199  if (rflow_req)
200  rflow_req->set_reverse_flow_entry(NULL);
201 
202  bool force_update_rflow = false;
203  if (fwd_flow_update) {
204  if (flow == NULL)
205  return;
206 
207  if (flow->deleted() || flow->IsShortFlow()) {
208  return;
209  }
210  }
211 
212  if (flow_req != flow) {
214  !flow->deleted()) {
215  // In this scenario packet trap for forward flow should
216  // not cause eviction of the reverse flow due to add event
217  // so trigger a force update instead of add for reverse flow
218  force_update_rflow = true;
219  }
220  Copy(flow, flow_req, fwd_flow_update);
221  flow->set_deleted(false);
222  // this flow entry is reused , increment the transaction id
223  // so that flow events with old transaction id will be ingnored
224  flow->IncrementTransactionId();
225  }
226 
227  if (rflow) {
228  if (rflow_req != rflow) {
229  Copy(rflow, rflow_req, (rev_flow_update || force_update_rflow));
230  // if the reverse flow was marked delete, reset its flow handle
231  // to invalid index to assure it is attempted to reprogram using
232  // kInvalidFlowHandle, this also ensures that flow entry wont
233  // give fake notion of being available in the flow index tree
234  // delete for which has already happend while triggering delete
235  // for flow entry
236  if (rflow->deleted()) {
238  // rflow was delete marked skip force update
239  force_update_rflow = false;
240  }
241  rflow->set_deleted(false);
242  // this flow entry is reused , increment the transaction id
243  // so that flow events with old transaction id will be ingnored
244  rflow->IncrementTransactionId();
245  } else {
246  // we are creating a new reverse flow, so avoid triggering
247  // force update in this case
248  force_update_rflow = false;
249  }
250  }
251 
252  if (flow) {
253  if (fwd_flow_update) {
255  } else {
257  }
258  }
259  if (rflow) {
260  if (rev_flow_update) {
262  } else {
264  }
265  }
266 
267  // If the flows are already present, we want to retain the Forward and
268  // Reverse flow characteristics for flow.
269  // We have following conditions,
270  // flow has ReverseFlow set, rflow has ReverseFlow reset
271  // Swap flow and rflow
272  // flow has ReverseFlow set, rflow has ReverseFlow set
273  // Unexpected case. Continue with flow as forward flow
274  // flow has ReverseFlow reset, rflow has ReverseFlow reset
275  // Unexpected case. Continue with flow as forward flow
276  // flow has ReverseFlow reset, rflow has ReverseFlow set
277  // No change in forward/reverse flow. Continue as forward-flow
279  rflow && !rflow->is_flags_set(FlowEntry::ReverseFlow)) {
280  FlowEntry *tmp = flow;
281  flow = rflow;
282  rflow = tmp;
283  }
284 
285  UpdateReverseFlow(flow, rflow);
286 
287  // Add the forward flow after adding the reverse flow first to avoid
288  // following sequence
289  // 1. Agent adds forward flow
290  // 2. vrouter releases the packet
291  // 3. Packet reaches destination VM and destination VM replies
292  // 4. Agent tries adding reverse flow. vrouter processes request in core-0
293  // 5. vrouter gets reverse packet in core-1
294  // 6. If (4) and (3) happen together, vrouter can allocate 2 hash entries
295  // for the flow.
296  //
297  // While the scenario above cannot be totally avoided, programming reverse
298  // flow first will reduce the probability
299  if (rflow) {
300  UpdateKSync(rflow, (rev_flow_update || force_update_rflow));
301  AddFlowInfo(rflow);
302  }
303 
304  UpdateKSync(flow, fwd_flow_update);
305  AddFlowInfo(flow);
306 }
307 
308 void FlowTable::DeleteInternal(FlowEntry *fe, uint64_t time,
309  const RevFlowDepParams &params) {
310  fe->set_deleted(true);
311 
312  // Unlink the reverse flow, if one exists
313  FlowEntry *rflow = fe->reverse_flow_entry();
314  if (rflow) {
315  rflow->set_reverse_flow_entry(NULL);
316  }
317  fe->set_reverse_flow_entry(NULL);
318 
319  ReleasePort(fe, true);
320 
321  DeleteFlowInfo(fe, params);
322  DeleteKSync(fe);
323 
325 }
326 
328  uint64_t time = UTCTimestampUsec();
329 
330  /* Fetch reverse-flow info for both flows before their reverse-flow
331  * links are broken. This info is required during FlowExport
332  *
333  * DeleteFlows() is invoked for both forward and reverse flows. So, get
334  * reverse-flow info only when flows are not deleted
335  */
336  RevFlowDepParams r_params;
337  if (rflow && rflow->deleted() == false) {
338  rflow->RevFlowDepInfo(&r_params);
339  }
340  if (flow && flow->deleted() == false) {
341  RevFlowDepParams f_params;
342  flow->RevFlowDepInfo(&f_params);
343  /* Delete the forward flow */
344  DeleteInternal(flow, time, f_params);
345  }
346 
347  if (rflow && rflow->deleted() == false) {
348  DeleteInternal(rflow, time, r_params);
349  }
350  return true;
351 }
352 
354  bool reverse_flow,
355  FlowEntry** flow,
356  FlowEntry** rflow) {
357  *flow = Find(key);
358  *rflow = NULL;
359 
360  //No flow entry, nothing to populate
361  if (!(*flow)) {
362  return;
363  }
364 
365  //No reverse flow requested, so dont populate rflow
366  if (!reverse_flow) {
367  return;
368  }
369 
370  FlowEntry *reverse_flow_entry = (*flow)->reverse_flow_entry();
371  if (reverse_flow_entry) {
372  *rflow = Find(reverse_flow_entry->key());
373  }
374 }
375 
376 //Caller makes sure lock is taken on flow.
377 bool FlowTable::DeleteUnLocked(bool del_reverse_flow,
378  FlowEntry *flow,
379  FlowEntry *rflow) {
380  if (!flow) {
381  return false;
382  }
383 
384  DeleteFlows(flow, rflow);
385 
386  //If deletion of reverse flow is to be done,
387  //make sure that rflow is populated if flow has a reverse flow pointer.
388  //In case rflow is not located with the reverse flow key, consider it as
389  //failure.
390  if (del_reverse_flow && flow->reverse_flow_entry() && !rflow) {
391  return false;
392  }
393  return true;
394 }
395 
396 //Caller has to ensure lock is taken for flow.
397 bool FlowTable::DeleteUnLocked(const FlowKey &key, bool del_reverse_flow) {
398  FlowEntry *flow = NULL;
399  FlowEntry *rflow = NULL;
400 
401  PopulateFlowEntriesUsingKey(key, del_reverse_flow, &flow, &rflow);
402  return DeleteUnLocked(del_reverse_flow, flow, rflow);
403 }
404 
405 bool FlowTable::Delete(const FlowKey &key, bool del_reverse_flow) {
406  FlowEntry *flow = NULL;
407  FlowEntry *rflow = NULL;
408 
409  PopulateFlowEntriesUsingKey(key, del_reverse_flow, &flow, &rflow);
410  FLOW_LOCK(flow, rflow, FlowEvent::DELETE_FLOW);
411  return DeleteUnLocked(del_reverse_flow, flow, rflow);
412 }
413 
415  FlowEntryMap::iterator it;
416 
417  it = flow_entry_map_.begin();
418  while (it != flow_entry_map_.end()) {
419  FlowEntry *entry = it->second;
420  FlowEntry *reverse_entry = NULL;
421  ++it;
422  if (it != flow_entry_map_.end() &&
423  it->second == entry->reverse_flow_entry()) {
424  reverse_entry = it->second;
425  ++it;
426  }
427  FLOW_LOCK(entry, reverse_entry, FlowEvent::DELETE_FLOW);
428  DeleteUnLocked(true, entry, reverse_entry);
429  }
430 }
431 
433  FlowEntry *flow_rev = flow->reverse_flow_entry();
434  FlowEntry *rflow_rev = NULL;
435 
436  if (rflow) {
437  rflow_rev = rflow->reverse_flow_entry();
438  }
439 
440  if (rflow_rev) {
441  assert(rflow_rev->reverse_flow_entry() == rflow);
442  rflow_rev->set_reverse_flow_entry(NULL);
443  }
444 
445  if (flow_rev) {
446  flow_rev->set_reverse_flow_entry(NULL);
447  }
448 
449  flow->set_reverse_flow_entry(rflow);
450  if (rflow) {
451  rflow->set_reverse_flow_entry(flow);
452  }
453 
454  if (flow_rev && (flow_rev->reverse_flow_entry() == NULL)) {
456  }
457 
458  if (rflow_rev && (rflow_rev->reverse_flow_entry() == NULL)) {
460  }
461 
462  if (flow->reverse_flow_entry() == NULL) {
464  }
465 
466  if (rflow && rflow->reverse_flow_entry() == NULL) {
468  }
469 
470  if (rflow) {
471  if (flow->is_flags_set(FlowEntry::ShortFlow) ||
474  }
475  if (flow->is_flags_set(FlowEntry::Multicast)) {
477  }
478  }
479 }
480 
483 }
484 
486 // Flow Info tree management
490 }
491 
494 }
495 
497 // Flow revluation routines. Processing will vary based on DBEntry type
500  return rand_gen_();
501 }
502 
503 // Enqueue message to recompute a flow
506  return;
507 
508  // If this is reverse flow, enqueue the corresponding forward flow
510  flow = flow->reverse_flow_entry();
511  }
512 
513  if (flow != NULL)
515 }
516 
517 // Handle deletion of a Route. Flow management module has identified that route
518 // must be deleted
520  DeleteUnLocked(true, flow, flow->reverse_flow_entry());
521 }
522 
523 void FlowTable::ReleasePort(FlowEntry *flow, bool evict) {
524  if (flow->allocated_port() == 0) {
525  return;
526  }
527 
529  pm->Free(flow->key(), flow->allocated_port(), evict);
530 }
531 
532 void FlowTable::EvictFlow(FlowEntry *flow, FlowEntry *reverse_flow,
533  uint32_t evict_gen_id) {
534  DisableKSyncSend(flow, evict_gen_id);
535  DeleteUnLocked(false, flow, NULL);
536 
537  // Reverse flow unlinked with forward flow. Make it short-flow
538  // Dont update ksync, it will shortly get either evicted or deleted by
539  // ageing process
540  if (reverse_flow)
542 }
543 
545  bool active_flow, bool deleted_flow) {
546  // Ignore revluate of deleted/short flows
547  if (flow->IsShortFlow())
548  return;
549 
550  if (flow->deleted())
551  return;
552 
553  FlowEntry *rflow = flow->reverse_flow_entry();
554  // Update may happen for reverse-flow. We act on both forward and
555  // reverse-flow. Get both forward and reverse flows
557  FlowEntry *tmp = flow;
558  flow = rflow;
559  rflow = tmp;
560  }
561 
562  // We want to update only if both forward and reverse flow are valid
563  if (flow == NULL || rflow == NULL)
564  return;
565 
566  // Ignore update, if any of the DBEntries referred is deleted
567  if (flow->vn_entry() && flow->vn_entry()->IsDeleted())
568  return;
569 
570  if (flow->rpf_nh() && flow->rpf_nh()->IsDeleted())
571  return;
572 
573  if (flow->intf_entry() && flow->intf_entry()->IsDeleted())
574  return;
575 
576  // Revaluate flood unknown-unicast flag. If flow has UnknownUnicastFlood and
577  // VN doesnt allow it, make Short Flow
578  if (flow->vn_entry() &&
579  flow->vn_entry()->flood_unknown_unicast() == false &&
582  }
583 
584  // On a l3mh compute, when physical interfaces state is down on host
585  // make all flows with underlay_gw_index same as phy intf encap index short
586  if (flow->data().underlay_gw_index_ != 0xff && agent()->is_l3mh()) {
587  InetUnicastRouteEntry *rt = NULL;
588  if (flow->is_flags_set(FlowEntry::IngressDir)) {
589  rt = static_cast<InetUnicastRouteEntry *>
591  } else if (rflow->is_flags_set(FlowEntry::IngressDir)) {
592  rt = static_cast<InetUnicastRouteEntry *>
593  (FlowEntry::GetUcRoute(rflow->GetDestinationVrf(), rflow->key().dst_addr));
594  }
595  if (rt != NULL) {
596  const TunnelNH *tunnel_nh =
597  dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
598  if (tunnel_nh != NULL) {
599  TunnelNH::EncapDataList encap_list = tunnel_nh->GetEncapDataList();
600  if (encap_list[flow->data().underlay_gw_index_].get()->valid_ == false) {
602  }
603  }
604  }
605  }
606  flow->UpdateL2RouteInfo();
607  rflow->UpdateL2RouteInfo();
608 
609  // Get policy attributes again and redo the flows
610  flow->GetPolicyInfo();
611  rflow->GetPolicyInfo();
612 
613  // Resync reverse flow first and then forward flow
614  // as forward flow resync will try to update reverse flow
615  rflow->ResyncFlow();
616  flow->ResyncFlow();
617 
618  // RPF computation can be done only after policy processing.
619  // Do RPF computation now
620  flow->RpfUpdate();
621  rflow->RpfUpdate();
622 
623  // the SG action could potentially have changed
624  // due to reflexive nature. Update KSync for reverse flow first
625  UpdateKSync(rflow, true);
626  UpdateKSync(flow, true);
627 
628  // Update flow-mgmt with new values
629  AddFlowInfo(flow);
630  AddFlowInfo(rflow);
631  return;
632 }
633 
635  FlowTableKSyncEntry *ksync_entry,
636  int ksync_error, uint32_t flow_handle,
637  uint32_t gen_id) {
638  // flow not associated with ksync anymore. Ignore the message
639  if (flow == NULL || flow != ksync_entry->flow_entry()) {
640  return;
641  }
642 
643  // VRouter can return EBADF and ENONENT error if flow-handle changed before
644  // getting KSync response back. Avoid making short-flow in such case
645  if ((ksync_error == EBADF || ksync_error == ENOENT)) {
646  if (flow->flow_handle() != flow_handle || flow->gen_id() != gen_id) {
647  return;
648  }
649  }
650 
651  // If VRouter returns error, mark the flow entry as short flow and
652  // update ksync error event to ksync index manager
653  //
654  // For EEXIST error donot mark the flow as ShortFlow since Vrouter
655  // generates EEXIST only for cases where another add should be
656  // coming from the pkt trap from Vrouter
657  if (ksync_error != EEXIST || flow->is_flags_set(FlowEntry::NatFlow)) {
658  // FIXME : We dont have good scheme to handle following scenario,
659  // - VM1 in VN1 has floating-ip FIP1 in VN2
660  // - VM2 in VN2
661  // - VM1 pings VM2 (using floating-ip)
662  // The forward and reverse flows go to different partitions.
663  //
664  // If packets for both forward and reverse flows are trapped together
665  // we try to setup following flows from different partitions,
666  // FlowPair-1
667  // - VM1 to VM2
668  // - VM2 to FIP1
669  // FlowPair-2
670  // - VM2 to FIP1
671  // - VM1 to VM2
672  //
673  // CEM-18166: BGPaaS corrupted NAT flow after repeated BGP session flap
674  // In the test environment it was observed that flows would remain stuck
675  // with old reverse indexes, after a few operations of disabling and
676  // re-enabling the interface on the VNF.
677  // A previous attempt to fix this in CEM-10354 proved to be incomplete.
678  // A better way to handle this case is to make the flows in question
679  // short, but since EEXIST is returned for the RF (from Controller), it
680  // is necessary to update the ksync_entry to the flow handle returned by
681  // vrouter DP, Agent does not know it and is thus -1.
682  if (flow->is_flags_set(FlowEntry::ReverseFlow) &&
683  ksync_error == EEXIST &&
685  KSyncFlowIndexManager *mgr =
687  mgr->UpdateFlowHandle(ksync_entry,
688  ksync_entry->ksync_response_info()->flow_handle_,
689  ksync_entry->ksync_response_info()->gen_id_);
691  return;
692  }
693  // The reverse flows for both FlowPair-1 and FlowPair-2 are not
694  // installed due to EEXIST error. We are converting flows to
695  // short-flow till this case is handled properly
697  }
698  if (ksync_error == EEXIST) {
699  const VmInterface *intf =
700  dynamic_cast<const VmInterface*>(flow->data().intf_entry.get());
701  KSyncFlowMemory *ksync_obj = agent()->ksync()->ksync_flow_memory();
702  const vr_flow_entry *kflow = ksync_obj->GetKernelFlowEntry(flow_handle, false);
703  if (kflow != nullptr &&
704  intf != nullptr &&
705  (kflow->fe_action != VR_FLOW_ACTION_HOLD)) {
707  KSyncFlowIndexManager *mgr =
709  mgr->UpdateFlowHandle(ksync_entry,
710  flow_handle, //ksync_entry->ksync_response_info()->flow_handle_,
711  gen_id); //ksync_entry->ksync_response_info()->gen_id_);
712  }
714  }
715  }
716  return;
717 }
718 
720 // KSync Routines
724  mgr->Delete(flow);
725 }
726 
727 void FlowTable::UpdateKSync(FlowEntry *flow, bool update) {
729  if (flow->deleted()) {
730  // ignore update on a deleted flow
731  // flow should already be non deleted of an Add case
732  assert(update == false);
733  return;
734  }
735  mgr->Update(flow);
736 }
737 
738 void FlowTable::DisableKSyncSend(FlowEntry *flow, uint32_t evict_gen_id) {
740  mgr->DisableSend(flow, evict_gen_id);
741 }
742 
744 // Link local flow information tree
746 void FlowTable::AddLinkLocalFlowInfo(int fd, uint32_t index, const FlowKey &key,
747  const uint64_t timestamp) {
748  std::scoped_lock mutext(mutex_);
749  LinkLocalFlowInfoMap::iterator it = linklocal_flow_info_map_.find(fd);
750  if (it == linklocal_flow_info_map_.end()) {
752  LinkLocalFlowInfoPair(fd, LinkLocalFlowInfo(index, key, timestamp)));
753  } else {
754  it->second.flow_index = index;
755  it->second.flow_key = key;
756  }
757 }
758 
760  std::scoped_lock mutext(mutex_);
761  linklocal_flow_info_map_.erase(fd);
762 }
763 
765 // Event handler routines
767 
768 // KSync flow event handler. Handles response for both vr_flow message only
770  FlowEntry *flow) {
771  FlowTableKSyncEntry *ksync_entry =
772  (static_cast<FlowTableKSyncEntry *> (req->ksync_entry()));
774 
775  // flow not associated with ksync anymore. Ignore the message
776  if (flow == NULL) {
777  return;
778  }
779 
780  // Ignore error for Delete messages
781  if (req->ksync_event() == KSyncEntry::DEL_ACK) {
782  return;
783  }
784 
785  // if transaction id is not same, then ignore the old
786  // vrouter add-ack response. this is possible that
787  // after vrouter add-ack response, flows will be evicted
788  // and new wflow with same flow tuple as evicted one will
789  // trigger new flow request to agent. this old add-ack response
790  // has no relevance, so should be ignored.
791  if (req->transaction_id() != flow->GetTransactionId()) {
792  return;
793  }
794 
795  if (req->ksync_error() != 0) {
796  // Handle KSync Errors
797  HandleKSyncError(flow, ksync_entry, req->ksync_error(),
798  req->flow_handle(), req->gen_id());
799  } else {
800  // Operation succeeded. Update flow-handle if not assigned
801  KSyncFlowIndexManager *mgr =
803  mgr->UpdateFlowHandle(ksync_entry, req->flow_handle(),
804  req->gen_id());
805  }
806 
807  // Log message if flow-handle change
809  if (flow->flow_handle() != req->flow_handle()) {
810  LOG(DEBUG, "Flow index changed from <"
811  << flow->flow_handle() << "> to <"
812  << req->flow_handle() << ">");
813  }
814  }
815 
816  // When vrouter allocates a flow-index or changes flow-handle, its
817  // possible that a flow in vrouter is evicted. Update stats for
818  // evicted flow
820  req->flow_handle() != flow->flow_handle()) {
821  FlowEntryPtr evicted_flow = imgr->FindByIndex(req->flow_handle());
822  if (evicted_flow.get() && evicted_flow->deleted() == false) {
824  mgr->FlowStatsUpdateEvent(evicted_flow.get(),
825  req->evict_flow_bytes(),
826  req->evict_flow_packets(),
827  req->evict_flow_oflow(),
828  evicted_flow->uuid());
829  }
830  }
831 
832  return;
833 }
834 
836  FlowEntry *rflow) {
837  //Take lock
838  FLOW_LOCK(flow, rflow, req->event());
839 
840  if (flow)
841  flow->set_last_event(req->event());
842  if (rflow)
843  rflow->set_last_event(req->event());
844  bool active_flow = true;
845  bool deleted_flow = flow->deleted();
846  if (deleted_flow || flow->is_flags_set(FlowEntry::ShortFlow))
847  active_flow = false;
848 
849  //Now process events.
850  switch (req->event()) {
851  case FlowEvent::DELETE_FLOW: {
852  //In case of continous stream of short lived TCP flows with same 5 tuple,
853  //flow eviction logic might cause below set of event
854  //1> F1 and R1 flow are added to flow table
855  //2> R1 is written to vrouter
856  //3> F1 is written to vrouter
857  //4> R1 flow add response is received, triggering update of
858  // F1(not needed now as reverse flow index is not written to kernel?)
859  //5> In the meantime flow is evicted in vrouter, hence flow update for F1
860  // would result in error from vrouter resulting in short flow
861  //6> Since F1 is shortflow Flow delete gets enqueued
862  //7> Since R1 is evict marked, flow evict gets enqueued
863  //8> Both event F1 and R1 delete and evict event can run in parallel,
864  // and hence reverse flow pointer obtained before FLOW lock could
865  // be invalid, hence read back the same
866  rflow = flow->reverse_flow_entry();
867  DeleteUnLocked(true, flow, rflow);
868  break;
869  }
870 
872  DeleteMessage(flow);
873  break;
874  }
875 
877  const DBEntry *entry = req->db_entry();
878  HandleRevaluateDBEntry(entry, flow, active_flow, deleted_flow);
879  break;
880  }
881 
883  if (active_flow)
884  RecomputeFlow(flow);
885  break;
886  }
887 
888  // Check if flow-handle changed. This can happen if vrouter tries to
889  // setup the flow which was evicted earlier
890  case FlowEvent::EVICT_FLOW: {
891  if (flow->flow_handle() != req->flow_handle() ||
892  flow->gen_id() != req->gen_id())
893  break;
894  EvictFlow(flow, rflow, req->evict_gen_id());
895  break;
896  }
897 
898  case FlowEvent::KSYNC_EVENT: {
899  const FlowEventKSync *ksync_event =
900  static_cast<const FlowEventKSync *>(req);
901  // Handle vr_flow message
902  ProcessKSyncFlowEvent(ksync_event, flow);
903  // Handle vr_response message
904  // Trigger the ksync flow event to move ksync state-machine
905  KSyncFlowIndexManager *imgr =
907  FlowTableKSyncEntry *ksync_entry = static_cast<FlowTableKSyncEntry *>
908  (ksync_event->ksync_entry());
909  imgr->TriggerKSyncEvent(ksync_entry, ksync_event->ksync_event());
910  break;
911  }
912 
914  if (flow->deleted()) {
915  break;
916  }
917 
919  flow->IncrementRetrycount();
920  } else {
922  flow->ResetRetryCount();
923  }
924 
925  UpdateKSync(flow, true);
926  break;
927  }
928 
929  default: {
930  assert(0);
931  break;
932  }
933  }
934  return true;
935 }
936 
938  std::string &action_str) {
939  std::bitset<32> bs(action_info.action);
940  for (unsigned int i = 0; i < bs.size(); i++) {
941  if (bs[i]) {
942  if (!action_str.empty()) {
943  action_str += "|";
944  }
945  action_str += TrafficAction::ActionToString(
946  static_cast<TrafficAction::Action>(i));
947  }
948  }
949 }
951 // FlowEntryFreeList implementation
954  free_list_.Grow();
956 }
957 
959  table_(table), max_count_(0), grow_pending_(false), total_alloc_(0),
960  total_free_(0), free_list_() {
961  uint32_t count = kInitCount;
962  if (table->agent()->test_mode()) {
963  count = kTestInitCount;
964  }
965 
966  while (max_count_ < count) {
967  free_list_.push_back(*new FlowEntry(table));
968  max_count_++;
969  }
970 }
971 
973  while (free_list_.empty() == false) {
974  FreeList::iterator it = free_list_.begin();
975  FlowEntry *flow = &(*it);
976  free_list_.erase(it);
977  delete flow;
978  }
979 }
980 
981 // Allocate a chunk of FlowEntries
983  assert(table_->ConcurrencyCheck(table_->flow_task_id()) == true);
984  grow_pending_ = false;
985  if (free_list_.size() >= kMinThreshold)
986  return;
987 
988  for (uint32_t i = 0; i < kGrowSize; i++) {
989  free_list_.push_back(*new FlowEntry(table_));
990  max_count_++;
991  }
992 }
993 
995  assert(table_->ConcurrencyCheck(table_->flow_task_id()) == true);
996  FlowEntry *flow = NULL;
997  if (free_list_.size() == 0) {
998  flow = new FlowEntry(table_);
999  max_count_++;
1000  } else {
1001  FreeList::iterator it = free_list_.begin();
1002  flow = &(*it);
1003  free_list_.erase(it);
1004  }
1005 
1006  if (grow_pending_ == false && free_list_.size() < kMinThreshold) {
1007  grow_pending_ = true;
1008  FlowProto *proto = table_->agent()->pkt()->get_flow_proto();
1009  proto->GrowFreeListRequest(table_);
1010  }
1011  flow->Reset(key);
1012  total_alloc_++;
1013  return flow;
1014 }
1015 
1017  // only flow logging task and flow event task can free up the flow entry ,
1018  assert((table_->ConcurrencyCheck(table_->flow_task_id()) == true) ||
1020  table_->flow_logging_task_id(), false) == true));
1021  total_free_++;
1022  flow->Reset();
1023  if (free_list_.size() < kMaxThreshold) {
1024  free_list_.push_back(*flow);
1025  assert(flow->flow_mgmt_info() == NULL);
1026  } else {
1027  delete flow;
1028  --max_count_;
1029  }
1030 }
#define kTaskFlowDelete
Definition: agent.h:326
#define kTaskFlowEvent
Definition: agent.h:323
#define kTaskFlowKSync
Definition: agent.h:324
#define kTaskFlowLogging
Definition: agent.h:329
#define kTaskFlowUpdate
Definition: agent.h:325
const NextHop * GetActiveNextHop() const
Definition: agent_route.cc:882
void incr_flow_created()
Definition: agent_stats.h:86
void incr_flow_aged()
Definition: agent_stats.h:106
Definition: agent.h:360
KSync * ksync() const
Definition: agent.cc:904
bool test_mode() const
Definition: agent.h:1193
TaskScheduler * task_scheduler() const
Definition: agent.h:1122
AgentStats * stats() const
Definition: agent.cc:884
PktModule * pkt() const
Definition: agent.cc:968
bool IsDeleted() const
Definition: db_entry.h:48
static const uint32_t kTestInitCount
Definition: flow_table.h:103
uint64_t total_alloc_
Definition: flow_table.h:128
virtual ~FlowEntryFreeList()
Definition: flow_table.cc:972
static const uint32_t kMaxThreshold
Definition: flow_table.h:106
FreeList free_list_
Definition: flow_table.h:130
FlowEntry * Allocate(const FlowKey &key)
Definition: flow_table.cc:994
static const uint32_t kMinThreshold
Definition: flow_table.h:105
FlowTable * table_
Definition: flow_table.h:125
void Free(FlowEntry *flow)
Definition: flow_table.cc:1016
static const uint32_t kInitCount
Definition: flow_table.h:102
uint64_t total_free_
Definition: flow_table.h:129
FlowEntryFreeList(FlowTable *table)
Definition: flow_table.cc:958
uint32_t max_count_
Definition: flow_table.h:126
static const uint32_t kGrowSize
Definition: flow_table.h:104
uint16_t allocated_port()
Definition: flow_entry.h:766
FlowEntry * reverse_flow_entry()
Definition: flow_entry.h:602
const FlowKey & key() const
Definition: flow_entry.h:594
bool IsShortFlow() const
Definition: flow_entry.h:682
const Interface * intf_entry() const
Definition: flow_entry.h:652
const NextHop * rpf_nh() const
Definition: flow_entry.h:658
static void Init()
Definition: flow_entry.cc:511
FlowData & data()
Definition: flow_entry.h:595
static const uint32_t kInvalidFlowHandle
Definition: flow_entry.h:521
static const uint32_t kFlowRetryAttempts
Definition: flow_entry.h:525
bool is_flags_set(const FlowEntryFlags &flags) const
Definition: flow_entry.h:610
uint32_t flow_handle() const
Definition: flow_entry.h:600
void set_flags(const FlowEntryFlags &flags)
Definition: flow_entry.h:613
uint8_t gen_id() const
Definition: flow_entry.h:599
void RpfUpdate()
Definition: flow_entry.cc:1394
void IncrementRetrycount()
Definition: flow_entry.h:747
FlowEntryInfo * flow_mgmt_info() const
Definition: flow_entry.h:760
uint32_t flow_handle_
Definition: flow_entry.h:818
void set_reverse_flow_entry(FlowEntry *reverse_flow_entry)
Definition: flow_entry.h:607
void ResetRetryCount()
Definition: flow_entry.h:748
static AgentRoute * GetUcRoute(const VrfEntry *entry, const IpAddress &addr)
Definition: flow_entry.cc:990
@ SHORT_REVERSE_FLOW_CHANGE
Definition: flow_entry.h:474
@ SHORT_NO_REVERSE_FLOW
Definition: flow_entry.h:473
@ SHORT_NO_MIRROR_ENTRY
Definition: flow_entry.h:481
@ SHORT_FAILED_VROUTER_INSTALL
Definition: flow_entry.h:478
@ SHORT_L3MH_PHY_INTF_DOWN
Definition: flow_entry.h:486
@ SHORT_NO_DST_ROUTE
Definition: flow_entry.h:470
void Copy(FlowEntry *rhs, bool update)
Definition: flow_entry.cc:532
void Reset(const FlowKey &k)
Definition: flow_entry.cc:506
const VrfEntry * GetDestinationVrf() const
Definition: flow_entry.cc:2688
void set_deleted(bool deleted)
Definition: flow_entry.h:719
void GetPolicyInfo(const VnEntry *vn, const FlowEntry *rflow)
Definition: flow_entry.cc:1679
void IncrementTransactionId()
Definition: flow_entry.h:769
void set_trace(bool val)
Definition: flow_entry.h:753
uint32_t GetTransactionId()
Definition: flow_entry.h:770
void MakeShortFlow(FlowShortReason reason)
Definition: flow_entry.cc:2922
bool deleted()
Definition: flow_entry.h:680
const VnEntry * vn_entry() const
Definition: flow_entry.h:653
void set_last_event(uint32_t event)
Definition: flow_entry.h:742
void RevFlowDepInfo(RevFlowDepParams *params)
Definition: flow_entry.cc:1078
void UpdateL2RouteInfo()
Definition: flow_entry.cc:2078
uint8_t GetMaxRetryAttempts()
Definition: flow_entry.h:746
@ BgpRouterService
Definition: flow_entry.h:549
@ UnknownUnicastFlood
Definition: flow_entry.h:548
void ResyncFlow()
Definition: flow_entry.cc:2670
uint64_t evict_flow_packets() const
Definition: flow_event.h:216
int ksync_error() const
Definition: flow_event.h:214
uint64_t evict_flow_oflow() const
Definition: flow_event.h:217
KSyncEntry::KSyncEvent ksync_event() const
Definition: flow_event.h:213
uint32_t transaction_id() const
Definition: flow_event.h:218
KSyncEntry * ksync_entry() const
Definition: flow_event.h:212
uint64_t evict_flow_bytes() const
Definition: flow_event.h:215
const DBEntry * db_entry() const
Definition: flow_event.h:150
uint32_t flow_handle() const
Definition: flow_event.h:156
uint32_t gen_id() const
Definition: flow_event.h:152
@ FLOW_MESSAGE
Definition: flow_event.h:23
@ KSYNC_EVENT
Definition: flow_event.h:54
@ EVICT_FLOW
Definition: flow_event.h:32
@ DELETE_FLOW
Definition: flow_event.h:25
@ RECOMPUTE_FLOW
Definition: flow_event.h:44
@ DELETE_DBENTRY
Definition: flow_event.h:36
@ UNRESOLVED_FLOW_ENTRY
Definition: flow_event.h:58
@ REVALUATE_DBENTRY
Definition: flow_event.h:40
@ VROUTER_FLOW_MSG
Definition: flow_event.h:21
uint32_t evict_gen_id() const
Definition: flow_event.h:153
Event event() const
Definition: flow_event.h:146
void FlowStatsUpdateEvent(FlowEntry *flow, uint32_t bytes, uint32_t packets, uint32_t oflow_bytes, const boost::uuids::uuid &u)
Definition: flow_mgmt.cc:174
void DeleteEvent(FlowEntry *flow, const RevFlowDepParams &params)
Definition: flow_mgmt.cc:159
void AddEvent(FlowEntry *low)
Definition: flow_mgmt.cc:147
void EnqueueUveDeleteEvent(const FlowEntry *flow) const
Definition: flow_mgmt.cc:565
void GrowFreeListRequest(FlowTable *table)
Definition: flow_proto.cc:627
bool ShouldTrace(const FlowEntry *flow, const FlowEntry *rflow)
Definition: flow_proto.cc:683
void MessageRequest(FlowEntry *flow)
Definition: flow_proto.cc:646
PortTableManager * port_table_manager()
Definition: flow_proto.h:128
const FlowKSyncResponseInfo * ksync_response_info() const
FlowEntryPtr flow_entry() const
bool DeleteFlows(FlowEntry *flow, FlowEntry *rflow)
Definition: flow_table.cc:327
Agent * agent_
Definition: flow_table.h:301
void Copy(FlowEntry *lhs, FlowEntry *rhs, bool update)
Definition: flow_table.cc:133
void Init()
Definition: flow_table.cc:77
FlowEntry * Find(const FlowKey &key)
Definition: flow_table.cc:121
Agent * agent() const
Definition: flow_table.h:207
static void GetFlowSandeshActionParams(const FlowAction &action_info, std::string &action_str)
Definition: flow_table.cc:937
FlowEntryFreeList free_list_
Definition: flow_table.h:310
int flow_logging_task_id() const
Definition: flow_table.h:266
FlowTableKSyncObject * ksync_object_
Definition: flow_table.h:304
void DelLinkLocalFlowInfo(int fd)
Definition: flow_table.cc:759
void RecomputeFlow(FlowEntry *flow)
Definition: flow_table.cc:504
void Shutdown()
Definition: flow_table.cc:90
void AddInternal(FlowEntry *flow, FlowEntry *new_flow, FlowEntry *rflow, FlowEntry *new_rflow, bool fwd_flow_update, bool rev_flow_update)
Definition: flow_table.cc:186
FlowEntry * Locate(FlowEntry *flow, uint64_t t)
Definition: flow_table.cc:147
void Add(FlowEntry *flow, FlowEntry *rflow)
Definition: flow_table.cc:160
void ReleasePort(FlowEntry *flow, bool evict)
Definition: flow_table.cc:523
void PopulateFlowEntriesUsingKey(const FlowKey &key, bool reverse_flow, FlowEntry **flow, FlowEntry **rflow)
Definition: flow_table.cc:353
std::mutex mutex_
Definition: flow_table.h:311
void DeleteAll()
Definition: flow_table.cc:414
void DisableKSyncSend(FlowEntry *flow, uint32_t evict_gen_id)
Definition: flow_table.cc:738
LinkLocalFlowInfoMap linklocal_flow_info_map_
Definition: flow_table.h:309
bool Delete(const FlowKey &key, bool del_reverse_flow)
Definition: flow_table.cc:405
int flow_task_id_
Definition: flow_table.h:312
void EvictFlow(FlowEntry *flow, FlowEntry *rflow, uint32_t evict_gen_id)
Definition: flow_table.cc:532
FlowTable(Agent *agent, uint16_t table_index)
Definition: flow_table.cc:59
bool ProcessFlowEvent(const FlowEvent *req, FlowEntry *flow, FlowEntry *rflow)
Definition: flow_table.cc:835
void ProcessKSyncFlowEvent(const FlowEventKSync *req, FlowEntry *flow)
Definition: flow_table.cc:769
void DeleteKSync(FlowEntry *flow)
Definition: flow_table.cc:722
void UpdateReverseFlow(FlowEntry *flow, FlowEntry *rflow)
Definition: flow_table.cc:432
virtual ~FlowTable()
Definition: flow_table.cc:73
void DeleteFlowUveInfo(FlowEntry *fe)
Definition: flow_table.cc:481
void UpdateKSync(FlowEntry *flow, bool update)
Definition: flow_table.cc:727
void HandleKSyncError(FlowEntry *flow, FlowTableKSyncEntry *ksync_entry, int ksync_error, uint32_t flow_handle, uint32_t gen_id)
Definition: flow_table.cc:634
void DeleteFlowInfo(FlowEntry *fe, const RevFlowDepParams &params)
Definition: flow_table.cc:492
int flow_ksync_task_id_
Definition: flow_table.h:315
boost::uuids::random_generator rand_gen_
Definition: flow_table.h:302
int flow_task_id() const
Definition: flow_table.h:262
boost::uuids::uuid rand_gen()
Definition: flow_table.cc:499
bool DeleteUnLocked(const FlowKey &key, bool del_reverse_flow)
Definition: flow_table.cc:397
void DeleteInternal(FlowEntry *fe, uint64_t t, const RevFlowDepParams &p)
Definition: flow_table.cc:308
void GrowFreeList()
Definition: flow_table.cc:953
FlowEntryMap flow_entry_map_
Definition: flow_table.h:305
int flow_logging_task_id_
Definition: flow_table.h:316
void InitDone()
Definition: flow_table.cc:87
std::pair< int, LinkLocalFlowInfo > LinkLocalFlowInfoPair
Definition: flow_table.h:181
int flow_delete_task_id_
Definition: flow_table.h:314
std::pair< FlowKey, FlowEntry * > FlowEntryMapPair
Definition: flow_table.h:168
uint16_t table_index_
Definition: flow_table.h:303
void AddLinkLocalFlowInfo(int fd, uint32_t index, const FlowKey &key, const uint64_t timestamp)
Definition: flow_table.cc:746
void Update(FlowEntry *flow, FlowEntry *rflow)
Definition: flow_table.cc:169
void HandleRevaluateDBEntry(const DBEntry *entry, FlowEntry *flow, bool active_flow, bool deleted_flow)
Definition: flow_table.cc:544
void AddFlowInfo(FlowEntry *fe)
Definition: flow_table.cc:488
void DeleteMessage(FlowEntry *flow)
Definition: flow_table.cc:519
int flow_update_task_id_
Definition: flow_table.h:313
bool ConcurrencyCheck(int task_id, bool check_task_instance)
Definition: flow_table.cc:96
void TriggerKSyncEvent(FlowTableKSyncEntry *kentry, KSyncEntry::KSyncEvent event)
void DisableSend(FlowEntry *flow, uint8_t evict_gen_id)
void Update(FlowEntry *flow)
void Delete(FlowEntry *flow)
FlowEntryPtr FindByIndex(uint32_t idx)
void UpdateFlowHandle(FlowTableKSyncEntry *kentry, uint32_t index, uint8_t gen_id)
const vr_flow_entry * GetKernelFlowEntry(uint32_t idx, bool ignore_active_status) const
KSyncFlowIndexManager * ksync_flow_index_manager() const
Definition: ksync_init.h:61
KSyncFlowMemory * ksync_flow_memory() const
Definition: ksync_init.h:58
FlowProto * get_flow_proto() const
Definition: pkt_init.h:43
FlowMgmtManager * flow_mgmt_manager(uint16_t index) const
Definition: pkt_init.h:39
void Free(const FlowKey &key, uint16_t port, bool release)
Definition: flow_entry.cc:4200
int GetTaskId(const std::string &name)
Definition: task.cc:861
Task is a class to describe a computational task within OpenSDN control plane applications....
Definition: task.h:79
static Task * Running()
Returns a pointer to the current task the code is executing under.
Definition: task.cc:1567
int task_code_id() const
Returns the code ID of this task.
Definition: task.h:133
int task_data_id() const
Returns the data ID of this task.
Definition: task.h:136
static std::string ActionToString(enum Action at)
std::vector< EncapDataPtr > EncapDataList
Definition: tunnel_nh.h:69
const EncapDataList GetEncapDataList() const
Definition: tunnel_nh.h:70
bool flood_unknown_unicast() const
Definition: vn.h:202
boost::intrusive_ptr< FlowEntry > FlowEntryPtr
Definition: flow_entry.h:125
SandeshTraceBufferPtr FlowTraceBuf(SandeshTraceBufferCreate("Flow", 5000))
#define FLOW_LOCK(flow, rflow, flow_event)
Definition: flow_table.h:61
#define LOG(_Level, _Msg)
Definition: logging.h:34
boost::shared_ptr< TraceBuffer< SandeshTrace > > SandeshTraceBufferPtr
Definition: sandesh_trace.h:18
SandeshTraceBufferPtr SandeshTraceBufferCreate(const std::string &buf_name, size_t buf_size, bool trace_enable=true)
Definition: sandesh_trace.h:46
Definition: acl.h:34
uint32_t action
Definition: acl.h:43
uint8_t underlay_gw_index_
Definition: flow_entry.h:361
InterfaceConstRef intf_entry
Definition: flow_entry.h:311
IpAddress dst_addr
Definition: flow_entry.h:214
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
boost::uuids::uuid uuid