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